From a31b5819566b94a2de3f7db8fc60ca9c06a1a8fa Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 13:11:26 -0500 Subject: [PATCH 01/57] Add offline mode prompt when zone check fails due to no internet When the zone status check fails with a network error, show a full-screen UI with an "Enable Offline Mode" button (matching the maintenance mode pattern) instead of the generic "Zone Check Failed" message. Also adds a red "No Internet" indicator in the zone status bar. Non-network errors retain the existing behavior. Co-Authored-By: Claude Opus 4.6 --- lib/screens/connection_screen.dart | 93 +++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index e186fe3..c0a4825 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -982,6 +982,11 @@ class _ConnectionScreenState extends State with WidgetsBinding locationIcon = Icons.engineering; locationText = 'Maintenance'; locationColor = Colors.orange; + // Network error: show wifi off indicator + } else if (appState.zoneCheckErrorReason == 'network') { + locationIcon = Icons.wifi_off; + locationText = 'No Internet'; + locationColor = Colors.red; // Show "Checking Zone..." whenever a zone check is in progress // This provides consistent UI feedback during both initial and re-checks } else if (appState.isCheckingZone) { @@ -1290,8 +1295,94 @@ class _ConnectionScreenState extends State with WidgetsBinding // Show zone checking status on initial startup (before zone is known) if (appState.inZone == null && !appState.offlineMode) { if (appState.zoneCheckError != null) { - // Zone check failed — show error with countdown final countdown = appState.zoneCheckRetryCountdown; + + // Network error — show offline mode option (matches maintenance pattern) + if (appState.zoneCheckErrorReason == 'network') { + return Column( + children: [ + _buildZoneStatusBar(context, appState), + Expanded( + child: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.wifi_off, + size: 64, + color: Colors.deepOrange.withValues(alpha: 0.7), + ), + const SizedBox(height: 16), + const Text( + 'No Internet Connection', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + 'Unable to reach MeshMapper. Check your connection, or wardrive offline.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + const SizedBox(height: 8), + Text( + countdown > 0 + ? 'Retrying in ${countdown}s...' + : 'Retrying...', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade500, + ), + ), + const SizedBox(height: 32), + FilledButton.icon( + onPressed: () => appState.setOfflineMode(true), + icon: const Icon(Icons.cloud_off), + label: const Text('Enable Offline Mode'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + ), + ), + const SizedBox(height: 32), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.withValues(alpha: 0.3)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.info_outline, size: 18, color: Colors.blue.shade700), + const SizedBox(width: 8), + Flexible( + child: Text( + 'Wardrive offline now, upload when service is restored.', + style: TextStyle(fontSize: 13, color: Colors.blue.shade700), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ); + } + + // Non-network errors — show simple error with countdown return Column( children: [ _buildZoneStatusBar(context, appState), From 65e81d3c87c0af19b90093c7dd71b1c4f8207144 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 13:40:12 -0500 Subject: [PATCH 02/57] Added option to disable carpeater RSSI filter under settings --- lib/models/user_preferences.dart | 16 +++++-- lib/providers/app_state_provider.dart | 35 +++++++++++++-- lib/screens/settings_screen.dart | 50 +++++++++++++++++++++ lib/services/meshcore/disc_tracker.dart | 9 +++- lib/services/meshcore/packet_validator.dart | 12 +++-- lib/services/meshcore/tx_tracker.dart | 10 ++++- lib/services/ping_service.dart | 13 ++++-- 7 files changed, 129 insertions(+), 16 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index 3eb4f57..2cdd1df 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -64,6 +64,9 @@ class UserPreferences { /// Map rotation lock (disable rotation gestures) final bool mapRotationLocked; + /// Disable RSSI carpeater filter (allow all signal strengths) + final bool disableRssiFilter; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -86,6 +89,7 @@ class UserPreferences { this.mapAutoFollow = false, this.mapAlwaysNorth = true, this.mapRotationLocked = false, + this.disableRssiFilter = false, }); /// Create from JSON (for persistence) @@ -112,6 +116,7 @@ class UserPreferences { mapAutoFollow: (json['mapAutoFollow'] as bool?) ?? false, mapAlwaysNorth: (json['mapAlwaysNorth'] as bool?) ?? true, mapRotationLocked: (json['mapRotationLocked'] as bool?) ?? false, + disableRssiFilter: (json['disableRssiFilter'] as bool?) ?? false, ); } @@ -139,6 +144,7 @@ class UserPreferences { 'mapAutoFollow': mapAutoFollow, 'mapAlwaysNorth': mapAlwaysNorth, 'mapRotationLocked': mapRotationLocked, + 'disableRssiFilter': disableRssiFilter, }; } @@ -165,6 +171,7 @@ class UserPreferences { bool? mapAutoFollow, bool? mapAlwaysNorth, bool? mapRotationLocked, + bool? disableRssiFilter, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -188,6 +195,7 @@ class UserPreferences { mapAutoFollow: mapAutoFollow ?? this.mapAutoFollow, mapAlwaysNorth: mapAlwaysNorth ?? this.mapAlwaysNorth, mapRotationLocked: mapRotationLocked ?? this.mapRotationLocked, + disableRssiFilter: disableRssiFilter ?? this.disableRssiFilter, ); } @@ -236,12 +244,13 @@ class UserPreferences { other.hybridModeEnabled == hybridModeEnabled && other.mapAutoFollow == mapAutoFollow && other.mapAlwaysNorth == mapAlwaysNorth && - other.mapRotationLocked == mapRotationLocked; + other.mapRotationLocked == mapRotationLocked && + other.disableRssiFilter == disableRssiFilter; } @override int get hashCode { - return Object.hash( + return Object.hashAll([ powerLevel, txPower, externalAntenna, @@ -262,7 +271,8 @@ class UserPreferences { mapAutoFollow, mapAlwaysNorth, mapRotationLocked, - ); + disableRssiFilter, + ]); } /// Check if using imperial units diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index a91f16f..6b4c1d8 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1010,7 +1010,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { hash: entry.value.hash, ); } - final newValidator = PacketValidator(allowedChannels: allowedChannels); + final newValidator = PacketValidator( + allowedChannels: allowedChannels, + disableRssiFilter: _preferences.disableRssiFilter, + ); _unifiedRxHandler!.updateValidator(newValidator); debugLog('[APP] PacketValidator updated with ${allowedChannels.length} channels: ' '${allowedChannelsData.values.map((c) => c.channelName).join(', ')}'); @@ -1029,6 +1032,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { deviceId: _deviceId, txTracker: _txTracker, audioService: _audioService, + disableRssiFilter: _preferences.disableRssiFilter, shouldIgnoreRepeater: (String repeaterId) { // Same filter as RxLogger - check user preferences for ignored repeater ID final prefs = _preferences; @@ -1398,6 +1402,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Create TX tracker (stored for use by PingService) _txTracker = TxTracker(); + _txTracker!.disableRssiFilter = _preferences.disableRssiFilter; // Log TX carpeater drops to error log (without navigating to error tab) _txTracker!.onCarpeaterDrop = (String repeaterId, String reason) { @@ -1617,8 +1622,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } debugLog('[APP] PacketValidator configured with ${allowedChannels.length} channels: ' '${allowedChannelsData.values.map((c) => c.channelName).join(', ')}'); - final validator = PacketValidator(allowedChannels: allowedChannels); - + final validator = PacketValidator( + allowedChannels: allowedChannels, + disableRssiFilter: _preferences.disableRssiFilter, + ); + // Create unified handler _unifiedRxHandler = UnifiedRxHandler( txTracker: _txTracker!, @@ -2718,10 +2726,31 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Saved antenna preference for "$deviceName": ${preferences.externalAntenna ? "external" : "device"}'); } + // Propagate RSSI filter setting to live trackers/validators + _syncRssiFilterSetting(preferences.disableRssiFilter); + notifyListeners(); _savePreferences(); } + /// Propagate disableRssiFilter to all active trackers and validators + void _syncRssiFilterSetting(bool disableRssiFilter) { + if (_txTracker != null) { + _txTracker!.disableRssiFilter = disableRssiFilter; + } + if (_unifiedRxHandler != null) { + final oldValidator = _unifiedRxHandler!.validator; + final newValidator = PacketValidator( + allowedChannels: oldValidator.allowedChannels, + disableRssiFilter: disableRssiFilter, + ); + _unifiedRxHandler!.updateValidator(newValidator); + } + if (_pingService != null) { + _pingService!.disableRssiFilter = disableRssiFilter; + } + } + /// Set developer mode (unlocked by tapping version 7 times) void setDeveloperMode(bool enabled) { _preferences = _preferences.copyWith(developerModeEnabled: enabled); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index b013208..7720c41 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -279,6 +279,23 @@ class _SettingsScreenState extends State { onTap: isAutoMode ? null : () => _showRepeaterIdDialog(context, appState), ), + // Disable RSSI Filter Toggle + SwitchListTile( + secondary: const Icon(Icons.shield_outlined), + title: const Text('Disable RSSI Filter'), + subtitle: Text(prefs.disableRssiFilter + ? 'Allows all signal strengths' + : 'Drops signals stronger than -30 dBm'), + value: prefs.disableRssiFilter, + onChanged: isAutoMode ? null : (value) { + if (value) { + _showDisableRssiFilterConfirmation(context, appState); + } else { + appState.updatePreferences(prefs.copyWith(disableRssiFilter: false)); + } + }, + ), + // Lock indicator if (isAutoMode) Padding( @@ -896,6 +913,39 @@ class _SettingsScreenState extends State { ); } + void _showDisableRssiFilterConfirmation(BuildContext context, AppStateProvider appState) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Disable RSSI Filter?'), + content: const Text( + 'By disabling this filter, you are confirming that you are not operating ' + 'a carpeater (a repeater co-located with your device).\n\n' + 'If this filter is disabled while a carpeater is present, your device will ' + 'report false coverage data to the MeshMapper community map. This degrades ' + 'map accuracy for everyone.\n\n' + 'Only disable this if you are certain no co-located repeater is within range.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + appState.updatePreferences( + appState.preferences.copyWith(disableRssiFilter: true), + ); + Navigator.pop(context); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Disable Filter'), + ), + ], + ), + ); + } + void _showHybridModeInfo(BuildContext context) { showDialog( context: context, diff --git a/lib/services/meshcore/disc_tracker.dart b/lib/services/meshcore/disc_tracker.dart index a836f3a..c9c1c5c 100644 --- a/lib/services/meshcore/disc_tracker.dart +++ b/lib/services/meshcore/disc_tracker.dart @@ -20,6 +20,9 @@ class DiscTracker { /// Callback to check if a repeater should be ignored (carpeater filter) final bool Function(String repeaterId)? shouldIgnoreRepeater; + /// When true, skip RSSI carpeater check (user setting) + final bool disableRssiFilter; + /// Callback for carpeater drops (for quiet error logging) /// Called with repeater ID and reason when a discovery response is dropped due to carpeater detection void Function(String repeaterId, String reason)? onCarpeaterDrop; @@ -28,7 +31,7 @@ class DiscTracker { /// Parameters: (node, isNew) - isNew is true for first time seeing this node void Function(DiscoveredNode node, bool isNew)? onNodeDiscovered; - DiscTracker({this.shouldIgnoreRepeater}); + DiscTracker({this.shouldIgnoreRepeater, this.disableRssiFilter = false}); /// Callback fired when discovery window completes void Function(List discoveredNodes)? onWindowComplete; @@ -141,7 +144,9 @@ class DiscTracker { } // Check RSSI (carpeater failsafe) - if (PacketValidator.isCarpeater(localRssi)) { + if (disableRssiFilter) { + debugLog('[DISC] RSSI filter disabled by user, skipping carpeater check'); + } else if (PacketValidator.isCarpeater(localRssi)) { debugLog('[DISC] ❌ DROPPED: RSSI too strong ($localRssi ≥ ${PacketValidator.maxRssiThreshold}) ' '- possible carpeater, repeater=$repeaterId'); onCarpeaterDrop?.call(repeaterId, 'RSSI too strong ($localRssi dBm)'); diff --git a/lib/services/meshcore/packet_validator.dart b/lib/services/meshcore/packet_validator.dart index 7e9b784..dfc9a8d 100644 --- a/lib/services/meshcore/packet_validator.dart +++ b/lib/services/meshcore/packet_validator.dart @@ -21,7 +21,10 @@ class PacketValidator { /// Allowed channels for validation final Map allowedChannels; - PacketValidator({required this.allowedChannels}); + /// When true, skip RSSI carpeater check (user setting) + final bool disableRssiFilter; + + PacketValidator({required this.allowedChannels, this.disableRssiFilter = false}); /// Validate packet for RX wardriving /// Returns ValidationResult with success/failure and reason @@ -37,12 +40,15 @@ class PacketValidator { 'PathLength: ${metadata.pathLength} | SNR: ${metadata.snr}'); // VALIDATION 1: Check RSSI (carpeater filter) - if (isCarpeater(metadata.rssi)) { + if (disableRssiFilter) { + debugLog('[RX FILTER] RSSI filter disabled by user, skipping carpeater check'); + } else if (isCarpeater(metadata.rssi)) { debugLog('[RX FILTER] ❌ DROPPED: RSSI too strong (${metadata.rssi} ≥ $maxRssiThreshold) - ' 'possible carpeater (RSSI failsafe)'); return ValidationResult.failed('carpeater-rssi'); + } else { + debugLog('[RX FILTER] ✓ RSSI OK (${metadata.rssi} < $maxRssiThreshold)'); } - debugLog('[RX FILTER] ✓ RSSI OK (${metadata.rssi} < $maxRssiThreshold)'); // VALIDATION 2: Check packet type if (metadata.isGroupText) { diff --git a/lib/services/meshcore/tx_tracker.dart b/lib/services/meshcore/tx_tracker.dart index 999a16d..cace3b8 100644 --- a/lib/services/meshcore/tx_tracker.dart +++ b/lib/services/meshcore/tx_tracker.dart @@ -34,6 +34,9 @@ class TxTracker { /// Returns true if the repeater should be filtered out bool Function(String repeaterId)? shouldIgnoreRepeater; + /// When true, skip RSSI carpeater check (user setting) + bool disableRssiFilter = false; + /// Start tracking echoes for a sent ping /// /// @param payload - The message text sent (for content verification) @@ -121,14 +124,17 @@ class TxTracker { } // VALIDATION STEP 2.5: Check RSSI (carpeater failsafe) - if (PacketValidator.isCarpeater(metadata.rssi)) { + if (disableRssiFilter) { + debugLog('[TX LOG] RSSI filter disabled by user, skipping carpeater check'); + } else if (PacketValidator.isCarpeater(metadata.rssi)) { debugLog('[TX LOG] ❌ DROPPED: RSSI too strong (${metadata.rssi} ≥ ${PacketValidator.maxRssiThreshold}) ' '- possible carpeater (RSSI failsafe), repeater=$pathHex'); debugLog('[TX LOG] onCarpeaterDrop callback is ${onCarpeaterDrop != null ? "SET" : "NULL"}'); onCarpeaterDrop?.call(pathHex, 'RSSI too strong (${metadata.rssi} dBm)'); return false; // Mark as handled (dropped) + } else { + debugLog('[TX LOG] ✓ RSSI OK (${metadata.rssi} < ${PacketValidator.maxRssiThreshold})'); } - debugLog('[TX LOG] ✓ RSSI OK (${metadata.rssi} < ${PacketValidator.maxRssiThreshold})'); // VALIDATION STEP 3: Channel hash validation if (metadata.encryptedPayload.length < 3) { diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 685cdbe..742428b 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -61,6 +61,9 @@ class PingService { final AudioService? _audioService; final bool Function(String repeaterId)? shouldIgnoreRepeater; + /// When true, skip RSSI carpeater check in DiscTracker (user setting) + bool disableRssiFilter; + PingStats _stats = const PingStats(); DateTime? _lastTxTime; Timer? _rxWindowTimer; @@ -159,6 +162,7 @@ class PingService { TxTracker? txTracker, AudioService? audioService, this.shouldIgnoreRepeater, + this.disableRssiFilter = false, }) : _gpsService = gpsService, _connection = connection, _apiQueue = apiQueue, @@ -884,8 +888,8 @@ class PingService { // Clear skip reason _skipReason = null; - // Clean up discovery infrastructure if hybrid was enabled - if (_hybridModeEnabled) { + // Clean up discovery infrastructure if passive or hybrid was enabled + if (_passiveModeEnabled || _hybridModeEnabled) { _stopDiscoveryMode(); } @@ -932,7 +936,10 @@ class PingService { debugLog('[DISC] Starting discovery mode'); // Create and configure discovery tracker - final tracker = DiscTracker(shouldIgnoreRepeater: shouldIgnoreRepeater); + final tracker = DiscTracker( + shouldIgnoreRepeater: shouldIgnoreRepeater, + disableRssiFilter: disableRssiFilter, + ); _discTracker = tracker; tracker.onCarpeaterDrop = onDiscCarpeaterDrop; tracker.onNodeDiscovered = (node, isNew) { From dd61de899134c50077ce91ce827f8513f7c46919 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 14:24:00 -0500 Subject: [PATCH 03/57] Multi-hop CARpeater packets now strip the CARpeater hop and report coverage from the underlying repeater with null SNR/RSSI, instead of being dropped entirely. Single-hop packets and discovery responses are still dropped. The -30 dBm failsafe is bypassed for packets matching your CARpeater prefix but stays active for everything else. --- .build_version | 2 +- lib/models/log_entry.dart | 36 +++++---- lib/models/ping_data.dart | 8 +- lib/providers/app_state_provider.dart | 87 +++++++++++---------- lib/screens/log_screen.dart | 24 ++++-- lib/screens/settings_screen.dart | 20 ++--- lib/services/meshcore/packet_validator.dart | 7 +- lib/services/meshcore/rx_logger.dart | 87 ++++++++++++++------- lib/services/meshcore/tx_tracker.dart | 77 ++++++++++++------ lib/services/ping_service.dart | 6 +- lib/widgets/map_widget.dart | 16 ++-- 11 files changed, 229 insertions(+), 141 deletions(-) diff --git a/.build_version b/.build_version index 7dea76e..9084fa2 100644 --- a/.build_version +++ b/.build_version @@ -1 +1 @@ -1.0.1 +1.1.0 diff --git a/lib/models/log_entry.dart b/lib/models/log_entry.dart index 758d4ab..399da9b 100644 --- a/lib/models/log_entry.dart +++ b/lib/models/log_entry.dart @@ -31,7 +31,7 @@ class TxLogEntry { String toCsv() { final eventsStr = events.isEmpty ? 'None' - : events.map((e) => '${e.repeaterId}(${e.snr.toStringAsFixed(2)})').join(','); + : events.map((e) => e.snr != null ? '${e.repeaterId}(${e.snr!.toStringAsFixed(2)})' : '${e.repeaterId}(null)').join(','); return '${timestamp.toIso8601String()},$latitude,$longitude,$power,$eventsStr'; } } @@ -39,21 +39,23 @@ class TxLogEntry { /// RX Event (repeater that heard a TX ping) class RxEvent { final String repeaterId; // Hex ID (e.g., "4e", "b7") - final double snr; // Signal-to-noise ratio in dB - final int rssi; // RSSI in dBm + final double? snr; // Signal-to-noise ratio in dB (null for CARpeater pass-through) + final int? rssi; // RSSI in dBm (null for CARpeater pass-through) RxEvent({ required this.repeaterId, - required this.snr, - this.rssi = 0, + this.snr, + this.rssi, }); /// Get SNR color severity (red, orange, green) + /// Returns null for CARpeater pass-through (no signal data) /// Reference: getSnrSeverityClass() in wardrive.js - SnrSeverity get severity { - if (snr <= -1) { + SnrSeverity? get severity { + if (snr == null) return null; + if (snr! <= -1) { return SnrSeverity.poor; // Red: -12 to -1 dB - } else if (snr <= 5) { + } else if (snr! <= 5) { return SnrSeverity.fair; // Orange: 0 to 5 dB } else { return SnrSeverity.good; // Green: 6 to 13+ dB @@ -66,8 +68,8 @@ class RxEvent { class RxLogEntry { final DateTime timestamp; final String repeaterId; // Hex ID (e.g., "4e", "b7") - final double snr; // Signal-to-noise ratio in dB - final int rssi; // Received signal strength indicator in dBm + final double? snr; // Signal-to-noise ratio in dB (null for CARpeater pass-through) + final int? rssi; // Received signal strength indicator in dBm (null for CARpeater pass-through) final int pathLength; // Number of hops final int header; // Packet header byte final double latitude; @@ -76,8 +78,8 @@ class RxLogEntry { RxLogEntry({ required this.timestamp, required this.repeaterId, - required this.snr, - required this.rssi, + this.snr, + this.rssi, required this.pathLength, required this.header, required this.latitude, @@ -97,10 +99,12 @@ class RxLogEntry { } /// Get SNR color severity - SnrSeverity get severity { - if (snr <= -1) { + /// Returns null for CARpeater pass-through (no signal data) + SnrSeverity? get severity { + if (snr == null) return null; + if (snr! <= -1) { return SnrSeverity.poor; - } else if (snr <= 5) { + } else if (snr! <= 5) { return SnrSeverity.fair; } else { return SnrSeverity.good; @@ -109,7 +113,7 @@ class RxLogEntry { /// Get CSV row String toCsv() { - return '${timestamp.toIso8601String()},$repeaterId,$snr,$rssi,' + return '${timestamp.toIso8601String()},$repeaterId,${snr ?? 'null'},${rssi ?? 'null'},' '$pathLength,0x${header.toRadixString(16).padLeft(2, '0')},' '$latitude,$longitude'; } diff --git a/lib/models/ping_data.dart b/lib/models/ping_data.dart index 2425d60..d9d52c8 100644 --- a/lib/models/ping_data.dart +++ b/lib/models/ping_data.dart @@ -111,14 +111,14 @@ class RxPing { /// Repeater that heard a TX ping (from echo tracking) class HeardRepeater { final String repeaterId; // Hex ID (e.g., "4e", "77") - final double snr; // Best SNR observed - final int rssi; // RSSI in dBm + final double? snr; // Best SNR observed (null for CARpeater pass-through) + final int? rssi; // RSSI in dBm (null for CARpeater pass-through) final int seenCount; // How many times this repeater was heard const HeardRepeater({ required this.repeaterId, - required this.snr, - this.rssi = 0, + this.snr, + this.rssi, this.seenCount = 1, }); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 6b4c1d8..d08103c 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1129,7 +1129,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Handle real-time echo updates - update TxLogEntry as echoes are received _pingService!.onEchoReceived = (txPing, repeater, isNew) { debugLog('[APP] ========== ECHO CALLBACK RECEIVED =========='); - debugLog('[APP] Real-time echo: ${repeater.repeaterId} (SNR: ${repeater.snr}, isNew: $isNew)'); + debugLog('[APP] Real-time echo: ${repeater.repeaterId} (SNR: ${repeater.snr ?? 'null'}, isNew: $isNew)'); debugLog('[APP] TxLogEntries count: ${_txLogEntries.length}'); // Find the matching TxLogEntry and update its events @@ -1216,8 +1216,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (lastTx.events.isNotEmpty) { repeaters = lastTx.events.map((e) => MarkerRepeaterInfo( repeaterId: e.repeaterId, - snr: e.snr, - rssi: e.rssi, + snr: e.snr ?? 0.0, + rssi: e.rssi ?? 0, )).toList(); } } @@ -1404,6 +1404,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _txTracker = TxTracker(); _txTracker!.disableRssiFilter = _preferences.disableRssiFilter; + // Set CARpeater prefix for pass-through (replaces shouldIgnoreRepeater) + _txTracker!.carpeaterPrefix = _preferences.ignoreCarpeater ? _preferences.ignoreRepeaterId : null; + debugLog('[APP] TxTracker.carpeaterPrefix set to ${_txTracker!.carpeaterPrefix ?? 'null'}'); + // Log TX carpeater drops to error log (without navigating to error tab) _txTracker!.onCarpeaterDrop = (String repeaterId, String reason) { debugLog('[APP] TX carpeater drop: repeater=$repeaterId, reason=$reason'); @@ -1412,37 +1416,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { }; debugLog('[APP] TxTracker.onCarpeaterDrop callback SET'); - // Function to check if repeater should be ignored (carpeater filter) - _txTracker!.shouldIgnoreRepeater = (String repeaterId) { - final prefs = _preferences; - if (prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null) { - final ignored = prefs.ignoreRepeaterId!.toUpperCase(); - return repeaterId.toUpperCase() == ignored; - } - return false; - }; - debugLog('[APP] TxTracker.shouldIgnoreRepeater callback SET'); - // Create RX logger (stored for use when enabling Passive Mode) _rxLogger = RxLogger( - // Function to check if repeater should be ignored (carpeater filter) - shouldIgnoreRepeater: (String repeaterId) { - // Check user preferences for ignored repeater ID - final prefs = _preferences; - if (prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null) { - // Case-insensitive comparison (both uppercase) - final ignored = prefs.ignoreRepeaterId!.toUpperCase(); - final current = repeaterId.toUpperCase(); - return current == ignored; - } - return false; - }, + // CARpeater prefix for pass-through (replaces shouldIgnoreRepeater) + carpeaterPrefix: _preferences.ignoreCarpeater ? _preferences.ignoreRepeaterId : null, // Immediate observation callback - fires when packet is first validated // Creates pin IMMEDIATELY for NEW repeaters (first time in current batch) onObservation: (observation) { try { debugLog('[APP] Immediate RX observation: repeater=${observation.repeaterId}, ' - 'snr=${observation.snr}, location=${observation.lat.toStringAsFixed(5)},${observation.lon.toStringAsFixed(5)}'); + 'snr=${observation.snr ?? 'null'}, location=${observation.lat.toStringAsFixed(5)},${observation.lon.toStringAsFixed(5)}'); // Log current batch tracking state for debugging debugLog('[APP] Current batch tracking: ${_currentBatchRepeaters.length} repeaters: $_currentBatchRepeaters'); @@ -1457,8 +1440,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { longitude: observation.lon, repeaterId: observation.repeaterId, timestamp: DateTime.now(), - snr: observation.snr, - rssi: observation.rssi, + snr: observation.snr ?? 0.0, + rssi: observation.rssi ?? 0, ); _rxPings.add(rxPing); if (_rxPings.length > _maxMapPins) _rxPings.removeAt(0); @@ -1480,8 +1463,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { repeaters: [ MarkerRepeaterInfo( repeaterId: observation.repeaterId, - snr: observation.snr, - rssi: observation.rssi, + snr: observation.snr ?? 0.0, + rssi: observation.rssi ?? 0, ), ], ); @@ -1501,7 +1484,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { try { debugLog('[APP] ========== BATCH FLUSH CALLBACK =========='); debugLog('[APP] Finalized RX entry (best SNR): repeater=${entry.repeaterId}, ' - 'snr=${entry.snr}, location=${entry.lat.toStringAsFixed(5)},${entry.lon.toStringAsFixed(5)}'); + 'snr=${entry.snr ?? 'null'}, location=${entry.lat.toStringAsFixed(5)},${entry.lon.toStringAsFixed(5)}'); final repeaterKey = entry.repeaterId.toUpperCase(); @@ -1518,20 +1501,22 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (lastPinIndex != -1) { // Update the pin's SNR to the best from this batch final existingPin = _rxPings[lastPinIndex]; - if (entry.snr > existingPin.snr) { + // Only update if new SNR is non-null and better (null never replaces non-null) + final shouldUpdateSnr = entry.snr != null && entry.snr! > existingPin.snr; + if (shouldUpdateSnr) { _rxPings[lastPinIndex] = RxPing( latitude: existingPin.latitude, // KEEP batch start location longitude: existingPin.longitude, // KEEP batch start location repeaterId: entry.repeaterId, timestamp: entry.timestamp, - snr: entry.snr, // UPDATE to best SNR from batch - rssi: entry.rssi, + snr: entry.snr ?? existingPin.snr, // UPDATE to best SNR from batch + rssi: entry.rssi ?? existingPin.rssi, ); debugLog('[APP] Updated RX pin SNR for repeater=${entry.repeaterId}: ' - '${existingPin.snr.toStringAsFixed(2)} -> ${entry.snr.toStringAsFixed(2)}'); + '${existingPin.snr.toStringAsFixed(2)} -> ${entry.snr?.toStringAsFixed(2) ?? 'null'}'); } else { debugLog('[APP] RX pin SNR unchanged for repeater=${entry.repeaterId}: ' - 'batch best ${entry.snr.toStringAsFixed(2)} <= pin ${existingPin.snr.toStringAsFixed(2)}'); + 'batch best ${entry.snr?.toStringAsFixed(2) ?? 'null'} <= pin ${existingPin.snr.toStringAsFixed(2)}'); } } else { // Edge case: pin not found (should have been created in onObservation) @@ -1540,8 +1525,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { longitude: entry.lon, repeaterId: entry.repeaterId, timestamp: entry.timestamp, - snr: entry.snr, - rssi: entry.rssi, + snr: entry.snr ?? 0.0, + rssi: entry.rssi ?? 0, ); _rxPings.add(newRxPing); if (_rxPings.length > _maxMapPins) _rxPings.removeAt(0); @@ -1571,13 +1556,15 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _rxLogEntries.add(rxLogEntry); if (_rxLogEntries.length > _maxLogEntries) _rxLogEntries.removeAt(0); debugLog('[APP] Added RX log entry: repeater=${entry.repeaterId}, ' - 'snr=${entry.snr}, pathLen=${entry.pathLength}'); + 'snr=${entry.snr ?? 'null'}, pathLen=${entry.pathLength}'); // Note: RX count is incremented in onObservation when pin is created (immediate feedback) // Enqueue to API with formatted heard_repeats string - // Format: "repeaterId(snr)" e.g. "4e(12.25)" - final heardRepeats = '${entry.repeaterId}(${entry.snr.toStringAsFixed(2)})'; + // Format: "repeaterId(snr)" e.g. "4e(12.25)" or "4e(null)" for CARpeater pass-through + final heardRepeats = entry.snr != null + ? '${entry.repeaterId}(${entry.snr!.toStringAsFixed(2)})' + : '${entry.repeaterId}(null)'; await _apiQueueService.enqueueRx( latitude: entry.lat, longitude: entry.lon, @@ -2729,10 +2716,26 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Propagate RSSI filter setting to live trackers/validators _syncRssiFilterSetting(preferences.disableRssiFilter); + // Propagate CARpeater prefix to live trackers + _syncCarpeaterPrefix(); + notifyListeners(); _savePreferences(); } + /// Propagate carpeaterPrefix to live TxTracker and RxLogger + void _syncCarpeaterPrefix() { + final prefix = _preferences.ignoreCarpeater ? _preferences.ignoreRepeaterId : null; + if (_txTracker != null) { + _txTracker!.carpeaterPrefix = prefix; + debugLog('[APP] Synced TxTracker.carpeaterPrefix = ${prefix ?? 'null'}'); + } + if (_rxLogger != null) { + _rxLogger!.carpeaterPrefix = prefix; + debugLog('[APP] Synced RxLogger.carpeaterPrefix = ${prefix ?? 'null'}'); + } + } + /// Propagate disableRssiFilter to all active trackers and validators void _syncRssiFilterSetting(bool disableRssiFilter) { if (_txTracker != null) { diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index bb8a6a3..9519772 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -488,13 +488,17 @@ class _TxLogTab extends StatelessWidget { snrColor = Colors.orange; case SnrSeverity.good: snrColor = Colors.green; + case null: + snrColor = Colors.grey; } // RSSI color based on signal strength Color rssiColor; - if (event.rssi >= -70) { + if (event.rssi == null) { + rssiColor = Colors.grey; + } else if (event.rssi! >= -70) { rssiColor = Colors.green; - } else if (event.rssi >= -100) { + } else if (event.rssi! >= -100) { rssiColor = Colors.orange; } else { rssiColor = Colors.red; @@ -511,13 +515,13 @@ class _TxLogTab extends StatelessWidget { // SNR Expanded( child: Center( - child: _buildTxChip(event.snr.toStringAsFixed(1), snrColor), + child: _buildTxChip(event.snr?.toStringAsFixed(1) ?? '-', snrColor), ), ), // RSSI Expanded( child: Center( - child: _buildTxChip('${event.rssi}', rssiColor), + child: _buildTxChip(event.rssi != null ? '${event.rssi}' : '-', rssiColor), ), ), ], @@ -591,13 +595,17 @@ class _RxLogTab extends StatelessWidget { snrColor = Colors.orange; case SnrSeverity.good: snrColor = Colors.green; + case null: + snrColor = Colors.grey; } // RSSI color based on signal strength Color rssiColor; - if (entry.rssi >= -70) { + if (entry.rssi == null) { + rssiColor = Colors.grey; + } else if (entry.rssi! >= -70) { rssiColor = Colors.green; // Strong: -30 to -70 dBm - } else if (entry.rssi >= -100) { + } else if (entry.rssi! >= -100) { rssiColor = Colors.orange; // Medium: -70 to -100 dBm } else { rssiColor = Colors.red; // Weak: -100 to -120 dBm @@ -721,13 +729,13 @@ class _RxLogTab extends StatelessWidget { // SNR Expanded( child: Center( - child: _buildRxChip(entry.snr.toStringAsFixed(1), snrColor), + child: _buildRxChip(entry.snr?.toStringAsFixed(1) ?? '-', snrColor), ), ), // RSSI Expanded( child: Center( - child: _buildRxChip('${entry.rssi}', rssiColor), + child: _buildRxChip(entry.rssi != null ? '${entry.rssi}' : '-', rssiColor), ), ), ], diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 7720c41..714d727 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -248,13 +248,13 @@ class _SettingsScreenState extends State { }, ), - // Carpeater Ignore Setting + // CARpeater Filter Setting SwitchListTile( secondary: const Icon(Icons.filter_alt), - title: const Text('Ignore Carpeater'), + title: const Text('CARpeater Filter'), subtitle: Text(prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null - ? 'Filtering repeater 0x${prefs.ignoreRepeaterId}' - : 'Tap to set repeater ID to ignore'), + ? 'Pass-through: stripping 0x${prefs.ignoreRepeaterId}' + : 'Tap to set CARpeater repeater ID'), value: prefs.ignoreCarpeater, onChanged: isAutoMode ? null : (value) { if (value && prefs.ignoreRepeaterId == null) { @@ -266,11 +266,11 @@ class _SettingsScreenState extends State { }, ), - // Repeater ID to Ignore - show when enabled + // CARpeater ID - show when enabled if (prefs.ignoreCarpeater) ListTile( leading: const SizedBox(width: 24), // Indent - title: const Text('Repeater ID'), + title: const Text('CARpeater ID'), subtitle: Text(prefs.ignoreRepeaterId != null ? '0x${prefs.ignoreRepeaterId}' : 'Not set'), @@ -1054,17 +1054,17 @@ class _SettingsScreenState extends State { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Ignore Repeater ID'), + title: const Text('CARpeater Repeater ID'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Enter the repeater ID to ignore (2 hex digits):'), + const Text('Enter the repeater ID of your CARpeater (2 hex digits):'), const SizedBox(height: 16), TextField( controller: controller, decoration: const InputDecoration( - labelText: 'Repeater ID', + labelText: 'CARpeater ID', hintText: 'FF', prefixText: '0x', border: OutlineInputBorder(), @@ -1084,7 +1084,7 @@ class _SettingsScreenState extends State { ), const SizedBox(height: 8), Text( - 'Enter 2-character hex ID (e.g., FF) to ignore a specific repeater.\nLeave empty to disable.', + 'Multi-hop packets through your CARpeater will be stripped to report the underlying repeater with null signal data. Single-hop CARpeater packets are still dropped.', style: TextStyle( fontSize: 12, color: Colors.grey[600], diff --git a/lib/services/meshcore/packet_validator.dart b/lib/services/meshcore/packet_validator.dart index dfc9a8d..7c11956 100644 --- a/lib/services/meshcore/packet_validator.dart +++ b/lib/services/meshcore/packet_validator.dart @@ -28,7 +28,8 @@ class PacketValidator { /// Validate packet for RX wardriving /// Returns ValidationResult with success/failure and reason - Future validate(PacketMetadata metadata) async { + /// [skipRssiCheck] - When true, skip the RSSI carpeater check (used for CARpeater pass-through) + Future validate(PacketMetadata metadata, {bool skipRssiCheck = false}) async { try { // Log packet for debugging final rawHex = metadata.raw @@ -40,7 +41,9 @@ class PacketValidator { 'PathLength: ${metadata.pathLength} | SNR: ${metadata.snr}'); // VALIDATION 1: Check RSSI (carpeater filter) - if (disableRssiFilter) { + if (skipRssiCheck) { + debugLog('[RX FILTER] RSSI check skipped (CARpeater pass-through)'); + } else if (disableRssiFilter) { debugLog('[RX FILTER] RSSI filter disabled by user, skipping carpeater check'); } else if (isCarpeater(metadata.rssi)) { debugLog('[RX FILTER] ❌ DROPPED: RSSI too strong (${metadata.rssi} ≥ $maxRssiThreshold) - ' diff --git a/lib/services/meshcore/rx_logger.dart b/lib/services/meshcore/rx_logger.dart index 64b3950..c20f675 100644 --- a/lib/services/meshcore/rx_logger.dart +++ b/lib/services/meshcore/rx_logger.dart @@ -34,12 +34,17 @@ class RxLogger { /// Called with repeater ID and reason when a packet is dropped due to carpeater detection final void Function(String repeaterId, String reason)? onCarpeaterDrop; + /// CARpeater prefix — when set, multi-hop packets with this firstHop are stripped + /// to report the underlying repeater with null SNR/RSSI + String? carpeaterPrefix; + RxLogger({ required this.onRxEntry, this.onObservation, required this.getGpsLocation, this.shouldIgnoreRepeater, this.onCarpeaterDrop, + this.carpeaterPrefix, }); /// Start passive RX wardriving @@ -73,11 +78,32 @@ class RxLogger { return false; } - // Extract LAST hop from path (the repeater that directly delivered to us) - // Do this early so we have repeater ID for carpeater logging - // Mask to last byte only (0xFF) for consistent 2-character display - final lastHopId = metadata.lastHop! & 0xFF; - final repeaterId = lastHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + // CARpeater pass-through: check firstHop against carpeaterPrefix + final firstHopId = metadata.firstHop!; + final firstHopHex = firstHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + bool carpeaterStripped = false; + String repeaterId; + double? reportedSnr = metadata.snr; + int? reportedRssi = metadata.rssi; + + if (carpeaterPrefix != null && firstHopHex == carpeaterPrefix!.toUpperCase()) { + if (metadata.pathLength < 2) { + debugLog('[RX LOG] CARpeater pass-through: single-hop, dropping'); + return false; + } + // Multi-hop: strip CARpeater, report underlying repeater (pathBytes[1]) + final underlyingHopId = metadata.pathBytes[1] & 0xFF; + repeaterId = underlyingHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + carpeaterStripped = true; + reportedSnr = null; + reportedRssi = null; + debugLog('[RX LOG] CARpeater pass-through: stripped $firstHopHex, reporting underlying repeater $repeaterId'); + } else { + // Normal path: extract LAST hop from path (the repeater that directly delivered to us) + // Mask to last byte only (0xFF) for consistent 2-character display + final lastHopId = metadata.lastHop! & 0xFF; + repeaterId = lastHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + } // Get current GPS location final gpsLocation = getGpsLocation(); @@ -89,13 +115,15 @@ class RxLogger { // Check if this repeater should be ignored (user carpeater filter) // Must run before RSSI check so user never sees confusing "RSSI too strong" // errors for a device they told the app to ignore - if (shouldIgnoreRepeater != null && shouldIgnoreRepeater!(repeaterId)) { + // Skip for CARpeater pass-through (CARpeater itself was already handled) + if (!carpeaterStripped && shouldIgnoreRepeater != null && shouldIgnoreRepeater!(repeaterId)) { debugLog('[RX LOG] ❌ Ignoring repeater $repeaterId (user carpeater filter)'); return false; } // PACKET FILTER: Validate packet before logging - final validation = await validator.validate(metadata); + // Skip RSSI check for CARpeater pass-through + final validation = await validator.validate(metadata, skipRssiCheck: carpeaterStripped); if (!validation.valid) { final rawHex = metadata.raw .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) @@ -110,16 +138,16 @@ class RxLogger { return false; } - debugLog('[RX LOG] Packet heard via last hop: $repeaterId, ' - 'SNR=${metadata.snr}, path_length=${metadata.pathLength}'); + debugLog('[RX LOG] Packet heard via ${carpeaterStripped ? 'underlying' : 'last'} hop: $repeaterId, ' + 'SNR=$reportedSnr, path_length=${metadata.pathLength}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); debugLog('[RX LOG] ✅ Packet validated and passed filter'); // Create observation for this packet final observation = RxObservation( repeaterId: repeaterId, - snr: metadata.snr, - rssi: metadata.rssi, + snr: reportedSnr, + rssi: reportedRssi, pathLength: metadata.pathLength, header: metadata.header, lat: gpsLocation.lat, @@ -132,8 +160,8 @@ class RxLogger { // Returns true if this observation updated the batch (new repeater or better SNR) final wasKept = await _handleRxBatching( repeaterId: repeaterId, - snr: metadata.snr, - rssi: metadata.rssi, + snr: reportedSnr, + rssi: reportedRssi, pathLength: metadata.pathLength, header: metadata.header, currentLocation: gpsLocation, @@ -149,10 +177,10 @@ class RxLogger { final batchedObservation = _batchBuffer[repeaterId]?.bestObservation ?? observation; onObservation?.call(batchedObservation); debugLog('[RX LOG] ✅ Observation kept in batch: repeater=$repeaterId, ' - 'snr=${batchedObservation.snr}, location=${batchedObservation.lat.toStringAsFixed(5)},${batchedObservation.lon.toStringAsFixed(5)}'); + 'snr=${batchedObservation.snr ?? 'null'}, location=${batchedObservation.lat.toStringAsFixed(5)},${batchedObservation.lon.toStringAsFixed(5)}'); } else { debugLog('[RX LOG] ⏭️ Observation ignored (worse SNR): repeater=$repeaterId, ' - 'snr=${metadata.snr}, current_best=${_batchBuffer[repeaterId]?.bestObservation.snr}'); + 'snr=$reportedSnr, current_best=${_batchBuffer[repeaterId]?.bestObservation.snr}'); } return true; @@ -168,8 +196,8 @@ class RxLogger { /// Returns true if this observation was kept (new repeater or better SNR) Future _handleRxBatching({ required String repeaterId, - required double snr, - required int rssi, + required double? snr, + required int? rssi, required int pathLength, required int header, required ({double lat, double lon}) currentLocation, @@ -207,9 +235,14 @@ class RxLogger { debugLog('[RX BATCH] Started 30s timeout timer for repeater $repeaterId'); } else { // Already tracking this repeater - check if new SNR is better - if (snr > buffer.bestObservation.snr) { + // Null SNR never replaces non-null; non-null always replaces null + final existingSnr = buffer.bestObservation.snr; + final shouldUpdate = snr != null && existingSnr != null + ? snr > existingSnr + : snr != null && existingSnr == null; + if (shouldUpdate) { debugLog('[RX BATCH] Better SNR for repeater $repeaterId: ' - '${buffer.bestObservation.snr} -> $snr'); + '$existingSnr -> $snr'); // IMPORTANT: Keep the FIRST location where we heard this repeater, // only update the SNR/RSSI/metadata. This ensures the map pin stays // at the original location and doesn't follow the user. @@ -423,8 +456,8 @@ class RxBatch { /// Single RX observation class RxObservation { final String repeaterId; // Hex ID of the repeater - final double snr; - final int rssi; + final double? snr; // Null for CARpeater pass-through + final int? rssi; // Null for CARpeater pass-through final int pathLength; final int header; final double lat; @@ -434,8 +467,8 @@ class RxObservation { RxObservation({ required this.repeaterId, - required this.snr, - required this.rssi, + this.snr, + this.rssi, required this.pathLength, required this.header, required this.lat, @@ -450,8 +483,8 @@ class RxApiEntry { final String repeaterId; final double lat; final double lon; - final double snr; - final int rssi; + final double? snr; // Null for CARpeater pass-through + final int? rssi; // Null for CARpeater pass-through final int pathLength; final int header; final DateTime timestamp; @@ -461,8 +494,8 @@ class RxApiEntry { required this.repeaterId, required this.lat, required this.lon, - required this.snr, - required this.rssi, + this.snr, + this.rssi, required this.pathLength, required this.header, required this.timestamp, diff --git a/lib/services/meshcore/tx_tracker.dart b/lib/services/meshcore/tx_tracker.dart index cace3b8..41a5a6b 100644 --- a/lib/services/meshcore/tx_tracker.dart +++ b/lib/services/meshcore/tx_tracker.dart @@ -22,9 +22,14 @@ class TxTracker { Timer? _windowTimer; + /// CARpeater prefix — when set, multi-hop packets with this firstHop are stripped + /// to report the underlying repeater with null SNR/RSSI + String? carpeaterPrefix; + /// Callback fired when a new echo is received (for real-time UI updates) /// Parameters: (repeaterId, snr, rssi, isNew) - isNew is true for first time seeing this repeater - void Function(String repeaterId, double snr, int rssi, bool isNew)? onEchoReceived; + /// snr/rssi are nullable for CARpeater pass-through (signal data is meaningless) + void Function(String repeaterId, double? snr, int? rssi, bool isNew)? onEchoReceived; /// Callback for carpeater drops (for quiet error logging) /// Called with repeater ID and reason when an echo is dropped due to carpeater detection @@ -81,7 +86,7 @@ class TxTracker { // Log final results if (repeaters.isNotEmpty) { for (final entry in repeaters.entries) { - debugLog('[TX LOG] Final: ${entry.key} -> SNR=${entry.value.snr}, seen=${entry.value.seenCount}x'); + debugLog('[TX LOG] Final: ${entry.key} -> SNR=${entry.value.snr ?? 'null'}, seen=${entry.value.seenCount}x'); } } } @@ -114,17 +119,40 @@ class TxTracker { // Extract first hop (first repeater) for use in validation and logging final firstHopId = metadata.firstHop!; - final pathHex = firstHopId.toRadixString(16).padLeft(2, '0'); + var pathHex = firstHopId.toRadixString(16).padLeft(2, '0'); + + // CARpeater pass-through: strip CARpeater hop and report underlying repeater + bool carpeaterStripped = false; + double? reportedSnr = metadata.snr; + int? reportedRssi = metadata.rssi; + + if (carpeaterPrefix != null && pathHex.toUpperCase() == carpeaterPrefix!.toUpperCase()) { + if (metadata.pathLength < 2) { + debugLog('[TX LOG] CARpeater pass-through: single-hop, dropping'); + return false; + } + // Multi-hop: strip CARpeater, report underlying repeater + final underlyingHopId = metadata.pathBytes[1] & 0xFF; + final underlyingHex = underlyingHopId.toRadixString(16).padLeft(2, '0'); + debugLog('[TX LOG] CARpeater pass-through: stripped $pathHex, reporting underlying repeater $underlyingHex'); + pathHex = underlyingHex; + carpeaterStripped = true; + reportedSnr = null; + reportedRssi = null; + } // VALIDATION STEP 2: Check user carpeater filter (before RSSI check so user // never sees confusing "RSSI too strong" errors for a device they told the app to ignore) - if (shouldIgnoreRepeater != null && shouldIgnoreRepeater!(pathHex.toUpperCase())) { + if (!carpeaterStripped && shouldIgnoreRepeater != null && shouldIgnoreRepeater!(pathHex.toUpperCase())) { debugLog('[TX LOG] ❌ DROPPED: Repeater $pathHex ignored by user carpeater filter'); return false; } // VALIDATION STEP 2.5: Check RSSI (carpeater failsafe) - if (disableRssiFilter) { + // Skip for CARpeater pass-through (user explicitly identified their CARpeater) + if (carpeaterStripped) { + debugLog('[TX LOG] RSSI check skipped (CARpeater pass-through)'); + } else if (disableRssiFilter) { debugLog('[TX LOG] RSSI filter disabled by user, skipping carpeater check'); } else if (PacketValidator.isCarpeater(metadata.rssi)) { debugLog('[TX LOG] ❌ DROPPED: RSSI too strong (${metadata.rssi} ≥ ${PacketValidator.maxRssiThreshold}) ' @@ -210,50 +238,53 @@ class TxTracker { // Path length and first hop already validated/extracted earlier (before RSSI check) - debugLog('[PING] Repeater echo accepted: first_hop=$pathHex, SNR=${metadata.snr}, ' - 'full_path_length=${metadata.pathLength}'); + debugLog('[PING] Repeater echo accepted: first_hop=$pathHex, SNR=$reportedSnr, ' + 'full_path_length=${metadata.pathLength}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); // Deduplication: check if we already have this repeater bool isNewRepeater = false; if (repeaters.containsKey(pathHex)) { final existing = repeaters[pathHex]!; debugLog('[PING] Deduplication: path $pathHex already seen ' - '(existing SNR=${existing.snr}, new SNR=${metadata.snr})'); + '(existing SNR=${existing.snr}, new SNR=$reportedSnr)'); - // Keep the best (highest) SNR - if (metadata.snr > existing.snr) { + // Keep the best (highest) SNR — null SNR never replaces non-null + final shouldUpdate = reportedSnr != null && existing.snr != null + ? reportedSnr > existing.snr! + : reportedSnr != null && existing.snr == null; + if (shouldUpdate) { debugLog('[PING] Deduplication decision: updating path $pathHex with better SNR: ' - '${existing.snr} -> ${metadata.snr}'); + '${existing.snr} -> $reportedSnr'); repeaters[pathHex] = RepeaterEcho( repeaterId: pathHex, - snr: metadata.snr, - rssi: metadata.rssi, + snr: reportedSnr, + rssi: reportedRssi, seenCount: existing.seenCount + 1, ); } else { debugLog('[PING] Deduplication decision: keeping existing SNR for path $pathHex ' - '(existing ${existing.snr} >= new ${metadata.snr})'); + '(existing ${existing.snr} >= new $reportedSnr)'); // Still increment seen count existing.seenCount++; } } else { // New repeater isNewRepeater = true; - debugLog('[PING] Adding new repeater echo: path=$pathHex, SNR=${metadata.snr}, RSSI=${metadata.rssi}'); + debugLog('[PING] Adding new repeater echo: path=$pathHex, SNR=$reportedSnr, RSSI=$reportedRssi'); repeaters[pathHex] = RepeaterEcho( repeaterId: pathHex, - snr: metadata.snr, - rssi: metadata.rssi, + snr: reportedSnr, + rssi: reportedRssi, seenCount: 1, ); } // Notify callback for real-time UI updates final bestSnr = repeaters[pathHex]!.snr; - final rssi = repeaters[pathHex]!.rssi; + final bestRssi = repeaters[pathHex]!.rssi; debugLog('[TX LOG] Invoking onEchoReceived callback (callback=${onEchoReceived != null ? "SET" : "NULL"})'); if (onEchoReceived != null) { - onEchoReceived!(pathHex, bestSnr, rssi, isNewRepeater); + onEchoReceived!(pathHex, bestSnr, bestRssi, isNewRepeater); debugLog('[TX LOG] onEchoReceived callback invoked successfully'); } @@ -275,14 +306,14 @@ class TxTracker { /// Repeater echo data class RepeaterEcho { final String repeaterId; // Hex string - double snr; // Best SNR seen - int rssi; // RSSI value (dBm) + double? snr; // Best SNR seen (null for CARpeater pass-through) + int? rssi; // RSSI value (dBm) (null for CARpeater pass-through) int seenCount; // Times observed RepeaterEcho({ required this.repeaterId, - required this.snr, - required this.rssi, + this.snr, + this.rssi, this.seenCount = 1, }); } diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 742428b..872eebd 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -651,8 +651,10 @@ class PingService { for (final entry in txTracker.repeaters.entries) { final repeaterId = entry.key; final echo = entry.value; - // Format SNR with 2 decimal places - repeaterStrings.add('$repeaterId(${echo.snr.toStringAsFixed(2)})'); + // Format SNR with 2 decimal places, or "null" for CARpeater pass-through + repeaterStrings.add(echo.snr != null + ? '$repeaterId(${echo.snr!.toStringAsFixed(2)})' + : '$repeaterId(null)'); debugLog('[PING] Heard repeater: $repeaterId, SNR=${echo.snr}'); } heardRepeats = repeaterStrings.join(','); diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 82dab78..2b256e7 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -1829,9 +1829,11 @@ class _MapWidgetState extends State with TickerProviderStateMixin { ...heardRepeaters.map((repeater) { // Calculate SNR chip color Color snrColor; - if (repeater.snr <= -1) { + if (repeater.snr == null) { + snrColor = Colors.grey; + } else if (repeater.snr! <= -1) { snrColor = Colors.red; - } else if (repeater.snr <= 5) { + } else if (repeater.snr! <= 5) { snrColor = Colors.orange; } else { snrColor = Colors.green; @@ -1839,9 +1841,11 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // Calculate RSSI chip color Color rssiColor; - if (repeater.rssi >= -70) { + if (repeater.rssi == null) { + rssiColor = Colors.grey; + } else if (repeater.rssi! >= -70) { rssiColor = Colors.green; - } else if (repeater.rssi >= -100) { + } else if (repeater.rssi! >= -100) { rssiColor = Colors.orange; } else { rssiColor = Colors.red; @@ -1859,7 +1863,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { Expanded( child: Center( child: _buildStatChip( - value: repeater.snr.toStringAsFixed(1), + value: repeater.snr?.toStringAsFixed(1) ?? '-', color: snrColor, ), ), @@ -1868,7 +1872,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { Expanded( child: Center( child: _buildStatChip( - value: '${repeater.rssi}', + value: repeater.rssi != null ? '${repeater.rssi}' : '-', color: rssiColor, ), ), From af64adca246469ac4977766a96d84a5d576619ee Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 21:26:17 -0500 Subject: [PATCH 04/57] Added Code of Conduct & Security --- CODE_OF_CONDUCT.md | 104 +++++++++++++++++++++++++++++++++++++++++++++ SECURITY.md | 62 +++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..89cf71b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,104 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a welcoming experience for everyone, regardless of background or +identity. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior: + +- Trolling, insulting or derogatory comments, and personal attacks +- Public or private harassment of any kind +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. + +## Enforcement + +Instances of unacceptable behavior may be reported to the project maintainers at +the [MeshMapper Project issue tracker](https://github.com/MeshMapper/MeshMapper_Project/issues). + +All complaints will be reviewed and investigated promptly and fairly. All +community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels. +Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, or targeted conduct +against an individual or group. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..b1e0339 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,62 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | --------- | +| Latest | Yes | + +Only the latest release on the `main` branch receives security updates. + +## Reporting a Vulnerability + +If you discover a security vulnerability in MeshMapper Flutter App, please report it responsibly. **Do not open a public GitHub issue for security vulnerabilities.** + +### How to Report + +1. Open a **private security advisory** at: + https://github.com/MeshMapper/MeshMapper_Flutter_App/security/advisories/new + +2. Include the following information: + - Description of the vulnerability + - Steps to reproduce + - Potential impact + - Suggested fix (if any) + +### What to Expect + +- **Acknowledgment**: We will acknowledge receipt of your report within 72 hours. +- **Assessment**: We will assess the severity and impact of the vulnerability. +- **Fix timeline**: Critical issues will be addressed as quickly as possible. We aim to release a fix within 30 days of confirmation. +- **Disclosure**: We will coordinate with you on public disclosure timing after a fix is available. + +## Security Considerations + +### API Key Handling + +- API keys are injected at build time via `--dart-define=API_KEY=...` and are **never** hardcoded in source code. + +### Bluetooth Security + +- The app communicates with MeshCore devices over Bluetooth Low Energy (BLE) using the MeshCore companion protocol. +- Channel messages are encrypted using AES-ECB with SHA-256 derived channel keys (encryption mode is dictated by the MeshCore protocol). + +### Data Privacy + +- GPS location data is sent to the MeshMapper API for community mesh coverage mapping. +- Users must be within a valid geographic zone (server-side validation) to submit data. +- No personal information beyond device name/public key and location data is transmitted. + +## Scope + +The following are **in scope** for security reports: + +- Vulnerabilities in the Flutter application code +- API key or secret exposure +- Authentication or session management issues +- Data leakage or privacy concerns + +The following are **out of scope**: + +- Vulnerabilities in third-party dependencies (report to the upstream project) +- Issues with the MeshCore firmware or radio protocol (report to the MeshCore project) \ No newline at end of file From 8936f896523e435e14649528e9bb0a0c11bed680 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 21:28:01 -0500 Subject: [PATCH 05/57] Update links --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index b1e0339..812bab3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,7 @@ If you discover a security vulnerability in MeshMapper Flutter App, please repor ### How to Report 1. Open a **private security advisory** at: - https://github.com/MeshMapper/MeshMapper_Flutter_App/security/advisories/new + https://github.com/MeshMapper/MeshMapper_Project/security/advisories/new 2. Include the following information: - Description of the vulnerability From bbd723b3fbc13adede0091d7fabab1e91c07006a Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Feb 2026 21:55:13 -0500 Subject: [PATCH 06/57] Exclude .vscode/ from version control Editor-specific configs shouldn't be tracked in a public repo so contributors can use their own setups. Co-Authored-By: Claude Opus 4.6 --- .gitignore | 5 +---- .vscode/tasks.json | 21 --------------------- 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore index 25d86f8..068e8e0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,10 +18,7 @@ migrate_working_dir/ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +.vscode/ # Flutter/Dart/Pub related **/doc/api/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index b7bd3c4..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Flutter: Build & Serve Web", - "type": "shell", - "command": " - ", - "isBackground": true, - "problemMatcher": [], - "group": "build", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "dedicated", - "showReuseMessage": false - } - } - ] -} \ No newline at end of file From ce4e538520fa28f2a4e442298ef88410d673e3e5 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Wed, 18 Feb 2026 09:41:27 -0500 Subject: [PATCH 07/57] Bug fixes: - [#98](https://github.com/MeshMapper/MeshMapper_Project/issues/98) - The heard repeaters panel now scrolls and dynamically expands to accommodate larger lists of heard repeaters - [#95](https://github.com/MeshMapper/MeshMapper_Project/issues/95) - Fixed the IATA popup panel being hidden behind the Android navigation bar - Fixed a bug where a stale BLE device name was used instead of the current one --- lib/providers/app_state_provider.dart | 25 +- lib/screens/home_screen.dart | 2 +- lib/widgets/map_widget.dart | 790 +++++++++++++------------- lib/widgets/status_bar.dart | 2 +- 4 files changed, 428 insertions(+), 391 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index d08103c..81686b3 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -708,8 +708,19 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ).listen( (device) { if (!_discoveredDevices.any((d) => d.id == device.id)) { - _discoveredDevices.add(device); - selectedDevice = device; + // Prefer remembered device name (from SelfInfo) over BLE cache + var enrichedDevice = device; + if (_rememberedDevice != null && device.id == _rememberedDevice!.id && + device.name != _rememberedDevice!.name) { + enrichedDevice = DiscoveredDevice( + id: device.id, + name: _rememberedDevice!.name, + rssi: device.rssi, + ); + debugLog('[SCAN] Using remembered name "${_rememberedDevice!.name}" instead of BLE name "${device.name}"'); + } + _discoveredDevices.add(enrichedDevice); + selectedDevice = enrichedDevice; notifyListeners(); } }, @@ -1311,6 +1322,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (selfInfoName != null && selfInfoName.isNotEmpty) { _displayDeviceName = selfInfoName; debugLog('[APP] Display name set from SelfInfo: "$selfInfoName"'); + + // Update remembered device with SelfInfo name + // BLE advertisement name may be stale after device rename + if (_rememberedDevice != null && _rememberedDevice!.id == device.id) { + final updatedName = 'MeshCore-$selfInfoName'; + if (_rememberedDevice!.name != updatedName) { + await _saveRememberedDevice(DiscoveredDevice(id: device.id, name: updatedName)); + debugLog('[APP] Updated remembered device name from SelfInfo: $updatedName'); + } + } } // Restore per-device antenna preference if previously saved diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index eacda81..07711e6 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -230,7 +230,7 @@ class _HomeScreenState extends State { borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) => Padding( - padding: const EdgeInsets.all(20), + padding: EdgeInsets.fromLTRB(20, 20, 20, 20 + MediaQuery.of(context).viewPadding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 2b256e7..f050615 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -1680,213 +1680,221 @@ class _MapWidgetState extends State with TickerProviderStateMixin { showModalBottomSheet( context: context, useSafeArea: true, + isScrollControlled: true, backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), - builder: (context) => Container( - padding: EdgeInsets.fromLTRB(20, 24, 20, 32 + MediaQuery.of(context).viewPadding.bottom), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // Header with icon badge - Row( + builder: (context) => ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.75, + ), + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.fromLTRB(20, 24, 20, 32 + MediaQuery.of(context).viewPadding.bottom), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - // Icon badge + // Header with icon badge + Row( + children: [ + // Icon badge + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.green.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.green.withValues(alpha: 0.4)), + ), + child: const Icon(Icons.arrow_upward, color: Colors.green, size: 24), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'TX Ping', + style: Theme.of(context).textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + Text( + _formatTime(ping.timestamp), + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + const SizedBox(height: 20), + + // Location chip Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( - color: Colors.green.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.green.withValues(alpha: 0.4)), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - child: const Icon(Icons.arrow_upward, color: Colors.green, size: 24), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( children: [ - Text( - 'TX Ping', - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w600, - ), - ), - Text( - _formatTime(ping.timestamp), - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.onSurfaceVariant, + Icon(Icons.location_on, size: 16, color: Theme.of(context).colorScheme.onSurfaceVariant), + const SizedBox(width: 8), + Expanded( + child: Text( + '${ping.latitude.toStringAsFixed(5)}, ${ping.longitude.toStringAsFixed(5)}', + style: TextStyle( + fontSize: 13, + fontFamily: 'monospace', + color: Theme.of(context).colorScheme.onSurface, + ), ), ), ], ), ), - IconButton( - icon: const Icon(Icons.close, size: 20), - onPressed: () => Navigator.pop(context), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - ], - ), - const SizedBox(height: 20), - - // Location chip - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), - ), - child: Row( - children: [ - Icon(Icons.location_on, size: 16, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(width: 8), - Expanded( - child: Text( - '${ping.latitude.toStringAsFixed(5)}, ${ping.longitude.toStringAsFixed(5)}', - style: TextStyle( - fontSize: 13, - fontFamily: 'monospace', - color: Theme.of(context).colorScheme.onSurface, - ), - ), + const SizedBox(height: 16), + + // Repeaters section header + Text( + heardRepeaters.isEmpty ? 'No repeaters heard' : 'Heard Repeaters (${heardRepeaters.length})', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurfaceVariant, + letterSpacing: 0.5, ), - ], - ), - ), - const SizedBox(height: 16), - - // Repeaters section header - Text( - heardRepeaters.isEmpty ? 'No repeaters heard' : 'Heard Repeaters (${heardRepeaters.length})', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.onSurfaceVariant, - letterSpacing: 0.5, - ), - ), - - if (heardRepeaters.isNotEmpty) ...[ - const SizedBox(height: 12), - // Repeaters table - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - child: Column( - children: [ - // Header row - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: Row( - children: [ - SizedBox( - width: 60, - child: Text( - 'Node', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - ], - ), + + if (heardRepeaters.isNotEmpty) ...[ + const SizedBox(height: 12), + // Repeaters table + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - Divider(height: 1, color: Theme.of(context).dividerColor), - // Data rows - ...heardRepeaters.map((repeater) { - // Calculate SNR chip color - Color snrColor; - if (repeater.snr == null) { - snrColor = Colors.grey; - } else if (repeater.snr! <= -1) { - snrColor = Colors.red; - } else if (repeater.snr! <= 5) { - snrColor = Colors.orange; - } else { - snrColor = Colors.green; - } - - // Calculate RSSI chip color - Color rssiColor; - if (repeater.rssi == null) { - rssiColor = Colors.grey; - } else if (repeater.rssi! >= -70) { - rssiColor = Colors.green; - } else if (repeater.rssi! >= -100) { - rssiColor = Colors.orange; - } else { - rssiColor = Colors.red; - } - - return InkWell( - onTap: () => RepeaterIdChip.showRepeaterPopup(context, repeater.repeaterId), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + children: [ + // Header row + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: Row( children: [ - // Repeater ID - RepeaterIdChip(repeaterId: repeater.repeaterId, fontSize: 13, width: 60), - // SNR + SizedBox( + width: 60, + child: Text( + 'Node', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), Expanded( - child: Center( - child: _buildStatChip( - value: repeater.snr?.toStringAsFixed(1) ?? '-', - color: snrColor, + child: Text( + 'SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), - // RSSI Expanded( - child: Center( - child: _buildStatChip( - value: repeater.rssi != null ? '${repeater.rssi}' : '-', - color: rssiColor, + child: Text( + 'RSSI', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), ], ), ), - ); - }), - ], - ), - ), - ], - ], + Divider(height: 1, color: Theme.of(context).dividerColor), + // Data rows + ...heardRepeaters.map((repeater) { + // Calculate SNR chip color + Color snrColor; + if (repeater.snr == null) { + snrColor = Colors.grey; + } else if (repeater.snr! <= -1) { + snrColor = Colors.red; + } else if (repeater.snr! <= 5) { + snrColor = Colors.orange; + } else { + snrColor = Colors.green; + } + + // Calculate RSSI chip color + Color rssiColor; + if (repeater.rssi == null) { + rssiColor = Colors.grey; + } else if (repeater.rssi! >= -70) { + rssiColor = Colors.green; + } else if (repeater.rssi! >= -100) { + rssiColor = Colors.orange; + } else { + rssiColor = Colors.red; + } + + return InkWell( + onTap: () => RepeaterIdChip.showRepeaterPopup(context, repeater.repeaterId), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + // Repeater ID + RepeaterIdChip(repeaterId: repeater.repeaterId, fontSize: 13, width: 60), + // SNR + Expanded( + child: Center( + child: _buildStatChip( + value: repeater.snr?.toStringAsFixed(1) ?? '-', + color: snrColor, + ), + ), + ), + // RSSI + Expanded( + child: Center( + child: _buildStatChip( + value: repeater.rssi != null ? '${repeater.rssi}' : '-', + color: rssiColor, + ), + ), + ), + ], + ), + ), + ); + }), + ], + ), + ), + ], + ], + ), + ), ), ), ); @@ -2106,254 +2114,262 @@ class _MapWidgetState extends State with TickerProviderStateMixin { showModalBottomSheet( context: context, useSafeArea: true, + isScrollControlled: true, backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), - builder: (context) => Container( - padding: EdgeInsets.fromLTRB(20, 24, 20, 32 + MediaQuery.of(context).viewPadding.bottom), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // Header with icon badge - Row( + builder: (context) => ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.75, + ), + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.fromLTRB(20, 24, 20, 32 + MediaQuery.of(context).viewPadding.bottom), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - // Icon badge + // Header with icon badge + Row( + children: [ + // Icon badge + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: _discMarkerColor.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: _discMarkerColor.withValues(alpha: 0.4)), + ), + child: const Icon(Icons.radar, color: _discMarkerColor, size: 24), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Disc Request', + style: Theme.of(context).textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + Text( + _formatTime(entry.timestamp), + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + const SizedBox(height: 20), + + // Location chip Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( - color: _discMarkerColor.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: _discMarkerColor.withValues(alpha: 0.4)), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - child: const Icon(Icons.radar, color: _discMarkerColor, size: 24), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( children: [ - Text( - 'Disc Request', - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w600, - ), - ), - Text( - _formatTime(entry.timestamp), - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.onSurfaceVariant, + Icon(Icons.location_on, size: 16, color: Theme.of(context).colorScheme.onSurfaceVariant), + const SizedBox(width: 8), + Expanded( + child: Text( + '${entry.latitude.toStringAsFixed(5)}, ${entry.longitude.toStringAsFixed(5)}', + style: TextStyle( + fontSize: 13, + fontFamily: 'monospace', + color: Theme.of(context).colorScheme.onSurface, + ), ), ), ], ), ), - IconButton( - icon: const Icon(Icons.close, size: 20), - onPressed: () => Navigator.pop(context), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - ], - ), - const SizedBox(height: 20), - - // Location chip - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), - ), - child: Row( - children: [ - Icon(Icons.location_on, size: 16, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(width: 8), - Expanded( - child: Text( - '${entry.latitude.toStringAsFixed(5)}, ${entry.longitude.toStringAsFixed(5)}', - style: TextStyle( - fontSize: 13, - fontFamily: 'monospace', - color: Theme.of(context).colorScheme.onSurface, - ), - ), + const SizedBox(height: 16), + + // Discovered nodes section header + Text( + entry.discoveredNodes.isEmpty + ? 'No nodes discovered' + : 'Discovered Nodes (${entry.discoveredNodes.length})', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurfaceVariant, + letterSpacing: 0.5, ), - ], - ), - ), - const SizedBox(height: 16), - - // Discovered nodes section header - Text( - entry.discoveredNodes.isEmpty - ? 'No nodes discovered' - : 'Discovered Nodes (${entry.discoveredNodes.length})', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.onSurfaceVariant, - letterSpacing: 0.5, - ), - ), - - if (entry.discoveredNodes.isNotEmpty) ...[ - const SizedBox(height: 12), - // Table with headers - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - child: Column( - children: [ - // Header row - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: Row( - children: [ - SizedBox( - width: 60, - child: Text( - 'Node', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'TX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - ], - ), + + if (entry.discoveredNodes.isNotEmpty) ...[ + const SizedBox(height: 12), + // Table with headers + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), ), - Divider(height: 1, color: Theme.of(context).dividerColor), - // Data rows - ...entry.discoveredNodes.map((node) { - // Calculate colors - Color rxSnrColor; - if (node.localSnr <= -1) { - rxSnrColor = Colors.red; - } else if (node.localSnr <= 5) { - rxSnrColor = Colors.orange; - } else { - rxSnrColor = Colors.green; - } - - Color rssiColor; - if (node.localRssi >= -70) { - rssiColor = Colors.green; - } else if (node.localRssi >= -100) { - rssiColor = Colors.orange; - } else { - rssiColor = Colors.red; - } - - Color txSnrColor; - if (node.remoteSnr <= -1) { - txSnrColor = Colors.red; - } else if (node.remoteSnr <= 5) { - txSnrColor = Colors.orange; - } else { - txSnrColor = Colors.green; - } - - return InkWell( - onTap: () => RepeaterIdChip.showRepeaterPopup(context, node.repeaterId, fullHexId: node.pubkeyHex), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + children: [ + // Header row + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: Row( children: [ - // Node ID with type SizedBox( width: 60, - child: Row( - children: [ - RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 13), - Text( - node.nodeTypeLabel, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: _discMarkerColor, - ), - ), - ], + child: Text( + 'Node', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ), ), - // RX SNR Expanded( - child: Center( - child: _buildStatChip( - value: node.localSnr.toStringAsFixed(1), - color: rxSnrColor, + child: Text( + 'RX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), - // RSSI Expanded( - child: Center( - child: _buildStatChip( - value: '${node.localRssi}', - color: rssiColor, + child: Text( + 'RX RSSI', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), - // TX SNR Expanded( - child: Center( - child: _buildStatChip( - value: node.remoteSnr.toStringAsFixed(1), - color: txSnrColor, + child: Text( + 'TX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), ], ), ), - ); - }), - ], - ), - ), - ], - ], + Divider(height: 1, color: Theme.of(context).dividerColor), + // Data rows + ...entry.discoveredNodes.map((node) { + // Calculate colors + Color rxSnrColor; + if (node.localSnr <= -1) { + rxSnrColor = Colors.red; + } else if (node.localSnr <= 5) { + rxSnrColor = Colors.orange; + } else { + rxSnrColor = Colors.green; + } + + Color rssiColor; + if (node.localRssi >= -70) { + rssiColor = Colors.green; + } else if (node.localRssi >= -100) { + rssiColor = Colors.orange; + } else { + rssiColor = Colors.red; + } + + Color txSnrColor; + if (node.remoteSnr <= -1) { + txSnrColor = Colors.red; + } else if (node.remoteSnr <= 5) { + txSnrColor = Colors.orange; + } else { + txSnrColor = Colors.green; + } + + return InkWell( + onTap: () => RepeaterIdChip.showRepeaterPopup(context, node.repeaterId, fullHexId: node.pubkeyHex), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + // Node ID with type + SizedBox( + width: 60, + child: Row( + children: [ + RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 13), + Text( + node.nodeTypeLabel, + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.w500, + color: _discMarkerColor, + ), + ), + ], + ), + ), + // RX SNR + Expanded( + child: Center( + child: _buildStatChip( + value: node.localSnr.toStringAsFixed(1), + color: rxSnrColor, + ), + ), + ), + // RSSI + Expanded( + child: Center( + child: _buildStatChip( + value: '${node.localRssi}', + color: rssiColor, + ), + ), + ), + // TX SNR + Expanded( + child: Center( + child: _buildStatChip( + value: node.remoteSnr.toStringAsFixed(1), + color: txSnrColor, + ), + ), + ), + ], + ), + ), + ); + }), + ], + ), + ), + ], + ], + ), + ), ), ), ); diff --git a/lib/widgets/status_bar.dart b/lib/widgets/status_bar.dart index c0904ff..90fa4af 100644 --- a/lib/widgets/status_bar.dart +++ b/lib/widgets/status_bar.dart @@ -57,7 +57,7 @@ class _StatusBarState extends State { borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) => Padding( - padding: const EdgeInsets.all(20), + padding: EdgeInsets.fromLTRB(20, 20, 20, 20 + MediaQuery.of(context).viewPadding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ From a47b49c9394fc47ffd7e74d8f583d5d22eececbb Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Wed, 18 Feb 2026 10:40:00 -0500 Subject: [PATCH 08/57] =?UTF-8?q?=20Anonymous=20Mode=20=E2=80=94=20New=20p?= =?UTF-8?q?rivacy=20option=20in=20Settings=20that=20renames=20your=20devic?= =?UTF-8?q?e=20to=20"Anonymous"=20for=20all=20mesh=20pings.=20When=20enabl?= =?UTF-8?q?ed,=20other=20mesh=20users=20cannot=20see=20your=20companion=20?= =?UTF-8?q?name=20in=20wardrive=20broadcasts.=20Your=20device's=20public?= =?UTF-8?q?=20key=20is=20still=20used=20to=20authenticate=20your=20session?= =?UTF-8?q?=20with=20the=20MeshMapper=20API=20(geo-auth),=20but=20neither?= =?UTF-8?q?=20your=20sessions=20nor=20=20=20your=20pings=20are=20linked=20?= =?UTF-8?q?to=20it=20on=20the=20server.=20Toggling=20Anonymous=20Mode=20wh?= =?UTF-8?q?ile=20connected=20automatically=20disconnects=20and=20reconnect?= =?UTF-8?q?s=20with=20the=20new=20identity,=20switching=20to=20the=20Conne?= =?UTF-8?q?ction=20tab=20so=20you=20can=20see=20reconnection=20progress.?= =?UTF-8?q?=20On=20proper=20disconnect,=20the=20original=20device=20name?= =?UTF-8?q?=20is=20restored.=20Persisted=20across=20app=20restarts.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/user_preferences.dart | 12 ++- lib/providers/app_state_provider.dart | 121 ++++++++++++++++++++++---- lib/screens/main_scaffold.dart | 12 +++ lib/screens/settings_screen.dart | 81 +++++++++++++++++ lib/services/meshcore/connection.dart | 8 ++ 5 files changed, 217 insertions(+), 17 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index 2cdd1df..a24e904 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -67,6 +67,9 @@ class UserPreferences { /// Disable RSSI carpeater filter (allow all signal strengths) final bool disableRssiFilter; + /// Anonymous mode: rename companion to "Anonymous" during wardriving + final bool anonymousMode; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -90,6 +93,7 @@ class UserPreferences { this.mapAlwaysNorth = true, this.mapRotationLocked = false, this.disableRssiFilter = false, + this.anonymousMode = false, }); /// Create from JSON (for persistence) @@ -117,6 +121,7 @@ class UserPreferences { mapAlwaysNorth: (json['mapAlwaysNorth'] as bool?) ?? true, mapRotationLocked: (json['mapRotationLocked'] as bool?) ?? false, disableRssiFilter: (json['disableRssiFilter'] as bool?) ?? false, + anonymousMode: (json['anonymousMode'] as bool?) ?? false, ); } @@ -145,6 +150,7 @@ class UserPreferences { 'mapAlwaysNorth': mapAlwaysNorth, 'mapRotationLocked': mapRotationLocked, 'disableRssiFilter': disableRssiFilter, + 'anonymousMode': anonymousMode, }; } @@ -172,6 +178,7 @@ class UserPreferences { bool? mapAlwaysNorth, bool? mapRotationLocked, bool? disableRssiFilter, + bool? anonymousMode, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -196,6 +203,7 @@ class UserPreferences { mapAlwaysNorth: mapAlwaysNorth ?? this.mapAlwaysNorth, mapRotationLocked: mapRotationLocked ?? this.mapRotationLocked, disableRssiFilter: disableRssiFilter ?? this.disableRssiFilter, + anonymousMode: anonymousMode ?? this.anonymousMode, ); } @@ -245,7 +253,8 @@ class UserPreferences { other.mapAutoFollow == mapAutoFollow && other.mapAlwaysNorth == mapAlwaysNorth && other.mapRotationLocked == mapRotationLocked && - other.disableRssiFilter == disableRssiFilter; + other.disableRssiFilter == disableRssiFilter && + other.anonymousMode == anonymousMode; } @override @@ -272,6 +281,7 @@ class UserPreferences { mapAlwaysNorth, mapRotationLocked, disableRssiFilter, + anonymousMode, ]); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 81686b3..73e7af3 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -160,6 +160,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // User preferences UserPreferences _preferences = const UserPreferences(); + // Anonymous mode state + String? _originalDeviceName; // Real name stored before rename + bool _isAnonymousRenamed = false; // Device currently renamed to "Anonymous" + /// Per-device antenna preferences: maps companion name → external antenna bool Map _deviceAntennaPreferences = {}; @@ -222,6 +226,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { int _mapNavigationTrigger = 0; // Increment to trigger navigation bool _requestMapTabSwitch = false; // Request switch to map tab bool _requestErrorLogSwitch = false; // Request switch to error log tab + bool _requestConnectionTabSwitch = false; // Request switch to connection tab // Repeater markers state List _repeaters = []; @@ -299,6 +304,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { int get mapNavigationTrigger => _mapNavigationTrigger; bool get requestMapTabSwitch => _requestMapTabSwitch; bool get requestErrorLogSwitch => _requestErrorLogSwitch; + bool get requestConnectionTabSwitch => _requestConnectionTabSwitch; UserPreferences get preferences => _preferences; RememberedDevice? get rememberedDevice => _rememberedDevice; @@ -341,6 +347,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get isSwitchingMode => _isSwitchingMode; String? get modeSwitchError => _modeSwitchError; + // Anonymous mode getter + bool get isAnonymousRenamed => _isAnonymousRenamed; + // Auto-reconnect getters bool get isAutoReconnecting => _isAutoReconnecting; int get reconnectAttempt => _reconnectAttempt; @@ -791,8 +800,29 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { return {'success': false, 'reason': 'no_public_key', 'message': 'Device public key not available'}; } - // Use SelfInfo name (user's configured name) if available, otherwise fall back to BLE advertisement name - final deviceName = _meshCoreConnection!.selfInfo?.name ?? connectedDeviceName?.replaceFirst('MeshCore-', ''); + // Anonymous mode: rename device before auth so mesh pings broadcast as "Anonymous" + if (_preferences.anonymousMode && !_isAnonymousRenamed) { + final realName = _meshCoreConnection!.selfInfo?.name; + if (realName != null && realName.isNotEmpty) { + _originalDeviceName = realName; + try { + await _meshCoreConnection!.setAdvertName('Anonymous'); + _isAnonymousRenamed = true; + _displayDeviceName = 'Anonymous'; + debugLog('[CONN] Anonymous mode: renamed from "$realName" to "Anonymous"'); + // Short delay for firmware to process + await Future.delayed(const Duration(milliseconds: 300)); + } catch (e) { + debugError('[CONN] Anonymous mode: rename failed: $e'); + // Continue with real name if rename fails + } + } + } + + // Resolve device name: use "Anonymous" if renamed, otherwise SelfInfo name + final deviceName = _isAnonymousRenamed + ? 'Anonymous' + : (_meshCoreConnection!.selfInfo?.name ?? connectedDeviceName?.replaceFirst('MeshCore-', '')); if (deviceName == null || deviceName.isEmpty) { debugError('[APP] Cannot request auth: could not retrieve device name'); return {'success': false, 'reason': 'no_device_name', 'message': 'Could not retrieve device name'}; @@ -950,9 +980,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Device public key stored: ${_devicePublicKey?.substring(0, 16) ?? 'null'}...'); // Persist device info for bug reports when disconnected - // Use companion name (selfInfo.name) or BLE device name with MeshCore- prefix stripped - var deviceName = _meshCoreConnection!.selfInfo?.name ?? - connectedDeviceName; + // Use original name (not "Anonymous") for bug report identification + var deviceName = _isAnonymousRenamed + ? _originalDeviceName + : (_meshCoreConnection!.selfInfo?.name ?? connectedDeviceName); if (deviceName != null) { // Always strip MeshCore- prefix if present deviceName = deviceName.replaceFirst('MeshCore-', ''); @@ -1320,13 +1351,15 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // BLE advertisement name may be cached/stale after device rename final selfInfoName = _meshCoreConnection?.selfInfo?.name; if (selfInfoName != null && selfInfoName.isNotEmpty) { - _displayDeviceName = selfInfoName; - debugLog('[APP] Display name set from SelfInfo: "$selfInfoName"'); + // Keep "Anonymous" display name if anonymous mode is active + _displayDeviceName = _isAnonymousRenamed ? 'Anonymous' : selfInfoName; + debugLog('[APP] Display name set: "$_displayDeviceName"'); - // Update remembered device with SelfInfo name + // Update remembered device with real name (not "Anonymous") // BLE advertisement name may be stale after device rename + final realName = _isAnonymousRenamed ? (_originalDeviceName ?? selfInfoName) : selfInfoName; if (_rememberedDevice != null && _rememberedDevice!.id == device.id) { - final updatedName = 'MeshCore-$selfInfoName'; + final updatedName = 'MeshCore-$realName'; if (_rememberedDevice!.name != updatedName) { await _saveRememberedDevice(DiscoveredDevice(id: device.id, name: updatedName)); debugLog('[APP] Updated remembered device name from SelfInfo: $updatedName'); @@ -1335,7 +1368,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } // Restore per-device antenna preference if previously saved - final resolvedName = displayDeviceName; + // Use original name for keying, not "Anonymous" + final resolvedName = _isAnonymousRenamed ? _originalDeviceName : displayDeviceName; if (resolvedName != null && _deviceAntennaPreferences.containsKey(resolvedName)) { final savedAntenna = _deviceAntennaPreferences[resolvedName]!; _preferences = _preferences.copyWith( @@ -1704,6 +1738,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + // Reset anonymous mode state (BLE already gone, can't restore name) + _isAnonymousRenamed = false; + _originalDeviceName = null; + // Existing cleanup _meshCoreConnection?.dispose(); _meshCoreConnection = null; @@ -1870,6 +1908,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _preferences = _preferences.copyWith(externalAntenna: false, externalAntennaSet: false); _savePreferences(); + // Reset anonymous mode state (BLE already gone, can't restore name) + _isAnonymousRenamed = false; + _originalDeviceName = null; + // Do full disconnect cleanup (releases API session, etc.) _fullDisconnectCleanup(); notifyListeners(); @@ -1931,6 +1973,20 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + // Restore original device name if anonymous mode renamed it (BLE must still be connected) + if (_isAnonymousRenamed && _originalDeviceName != null) { + try { + await _meshCoreConnection?.setAdvertName(_originalDeviceName!); + debugLog('[CONN] Anonymous mode: restored name to "$_originalDeviceName"'); + } catch (e) { + debugError('[CONN] Anonymous mode: failed to restore name: $e'); + logError('Anonymous Mode: Failed to restore device name. Device may still show as "Anonymous".', + severity: ErrorSeverity.warning, autoSwitch: false); + } + _isAnonymousRenamed = false; + _originalDeviceName = null; + } + // Delete wardriving channel FIRST, while BLE connection is still active // This prevents "GATT Server is disconnected" errors await _meshCoreConnection?.deleteWardrivingChannelEarly(); @@ -2391,8 +2447,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { await _saveOfflineSession(); // 4. Request new auth session - final deviceName = _meshCoreConnection?.selfInfo?.name ?? - connectedDeviceName?.replaceFirst('MeshCore-', ''); + // Use "Anonymous" if renamed, otherwise real name + final deviceName = _isAnonymousRenamed + ? 'Anonymous' + : (_meshCoreConnection?.selfInfo?.name ?? + connectedDeviceName?.replaceFirst('MeshCore-', '')); if (deviceName == null || deviceName.isEmpty) { debugError('[APP] Cannot switch to online mode: no device name available'); @@ -2551,12 +2610,15 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { return; } - // Include device info for auth during upload (same priority as online auth: SelfInfo name → BLE name) + // Include device info for auth during upload (use real name, not "Anonymous" — sessions upload later) // Note: Connection already validates device name exists, so this should never be null + final offlineDeviceName = _isAnonymousRenamed + ? _originalDeviceName + : (_meshCoreConnection?.selfInfo?.name ?? connectedDeviceName?.replaceFirst('MeshCore-', '')); await _offlineSessionService.saveSession( pings, devicePublicKey: _devicePublicKey, - deviceName: _meshCoreConnection?.selfInfo?.name ?? connectedDeviceName?.replaceFirst('MeshCore-', ''), + deviceName: offlineDeviceName, ); debugLog('[APP] Saved offline session with ${pings.length} pings'); notifyListeners(); @@ -2726,8 +2788,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Clear restored flag — user is making a manual choice now _antennaRestoredFromDevice = false; - // Persist antenna choice per device name - final deviceName = displayDeviceName; + // Persist antenna choice per device name (use original name, not "Anonymous") + final deviceName = _isAnonymousRenamed ? _originalDeviceName : displayDeviceName; if (deviceName != null && preferences.externalAntennaSet) { _deviceAntennaPreferences[deviceName] = preferences.externalAntenna; _saveDeviceAntennaPreferences(); @@ -2744,6 +2806,28 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _savePreferences(); } + /// Set anonymous mode, disconnecting and reconnecting if currently connected + Future setAnonymousMode(bool enabled) async { + if (enabled == _preferences.anonymousMode) return; + + _preferences = _preferences.copyWith(anonymousMode: enabled); + _savePreferences(); + notifyListeners(); + + // If connected, disconnect and reconnect for clean auth session + if (_connectionStatus == ConnectionStatus.connected && _meshCoreConnection != null) { + final deviceToReconnect = _bluetoothService.connectedDevice; + if (deviceToReconnect != null) { + _requestConnectionTabSwitch = true; + notifyListeners(); + await disconnect(); // Full cleanup (restores name if previously anonymous) + // Short delay for BLE cleanup + await Future.delayed(const Duration(milliseconds: 500)); + await connectToDevice(deviceToReconnect); + } + } + } + /// Propagate carpeaterPrefix to live TxTracker and RxLogger void _syncCarpeaterPrefix() { final prefix = _preferences.ignoreCarpeater ? _preferences.ignoreRepeaterId : null; @@ -2869,6 +2953,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _requestErrorLogSwitch = false; } + /// Clear the connection tab switch request (called by main scaffold after switching) + void clearConnectionTabSwitchRequest() { + _requestConnectionTabSwitch = false; + } + // ============================================ // API Error Handling // ============================================ diff --git a/lib/screens/main_scaffold.dart b/lib/screens/main_scaffold.dart index b0bc903..cd28c2c 100644 --- a/lib/screens/main_scaffold.dart +++ b/lib/screens/main_scaffold.dart @@ -149,6 +149,18 @@ class _MainScaffoldState extends State { }); } + // Listen for connection tab requests - switch to Connect tab (e.g. anonymous mode reconnect) + if (appState.requestConnectionTabSwitch && _selectedIndex != 3) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + setState(() { + _selectedIndex = 3; // Switch to Connect tab + }); + appState.clearConnectionTabSwitchRequest(); + } + }); + } + final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; return Scaffold( diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 714d727..07d8078 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -14,6 +14,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import '../utils/web_file_helpers_stub.dart' if (dart.library.html) '../utils/web_file_helpers.dart'; +import '../models/connection_state.dart'; import '../providers/app_state_provider.dart'; import '../utils/debug_logger_io.dart'; import '../utils/distance_formatter.dart'; @@ -279,6 +280,27 @@ class _SettingsScreenState extends State { onTap: isAutoMode ? null : () => _showRepeaterIdDialog(context, appState), ), + // Anonymous Mode Toggle + SwitchListTile( + secondary: const Icon(Icons.visibility_off), + title: const Text('Anonymous Mode'), + subtitle: Text(prefs.anonymousMode + ? 'Device broadcasts as "Anonymous"' + : 'Device uses its real name'), + value: prefs.anonymousMode, + onChanged: isAutoMode ? null : (value) { + if (value) { + _showEnableAnonymousConfirmation(context, appState); + } else { + if (appState.connectionStatus == ConnectionStatus.connected) { + _showDisableAnonymousConfirmation(context, appState); + } else { + appState.setAnonymousMode(false); + } + } + }, + ), + // Disable RSSI Filter Toggle SwitchListTile( secondary: const Icon(Icons.shield_outlined), @@ -946,6 +968,65 @@ class _SettingsScreenState extends State { ); } + void _showEnableAnonymousConfirmation(BuildContext context, AppStateProvider appState) { + final isConnected = appState.connectionStatus == ConnectionStatus.connected; + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Enable Anonymous Mode?'), + content: Text( + 'Your device will be renamed to "Anonymous" for all mesh pings. ' + 'Other mesh users will not see your companion name.\n\n' + 'Your public key is still used to authenticate your session, but ' + 'neither your sessions nor your pings are linked to it on the server.\n\n' + '${isConnected ? 'Your device will disconnect and reconnect automatically.\n\n' : ''}' + 'If the app crashes or BLE disconnects unexpectedly, your device ' + 'may remain named "Anonymous" until you reconnect and properly disconnect. ' + 'Always use the Disconnect button to restore your device name.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + appState.setAnonymousMode(true); + }, + style: TextButton.styleFrom(foregroundColor: Colors.orange), + child: const Text('Enable'), + ), + ], + ), + ); + } + + void _showDisableAnonymousConfirmation(BuildContext context, AppStateProvider appState) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Disable Anonymous Mode?'), + content: const Text( + 'This will disconnect and reconnect your device to restore your companion name. Continue?', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + appState.setAnonymousMode(false); + }, + child: const Text('Continue'), + ), + ], + ), + ); + } + void _showHybridModeInfo(BuildContext context) { showDialog( context: context, diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index 0292a28..acf90d4 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -725,6 +725,14 @@ class MeshCoreConnection { await _sendToRadio(data); } + /// Set the companion advertised name + Future setAdvertName(String name) async { + final data = BufferWriter(); + data.writeByte(CommandCodes.setAdvertName); + data.writeString(name); + await _sendToRadio(data); + } + /// Set radio parameters Future setRadioParams(int freq, int bw, int sf, int cr) async { final data = BufferWriter(); From 861c09df95bc322952801447b77af9d2b3154824 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Wed, 18 Feb 2026 12:46:41 -0500 Subject: [PATCH 09/57] Update repeater endpoint from /repeaters.json to /get_repeaters.php Co-Authored-By: Claude Opus 4.6 --- lib/services/api_service.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 717b232..885e005 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -682,7 +682,7 @@ class ApiService { /// Returns a list of enabled repeaters for the given IATA zone code Future> fetchRepeaters(String iata) async { final stopwatch = Stopwatch()..start(); - const endpoint = '/repeaters.json'; + const endpoint = '/get_repeaters.php'; try { final url = 'https://${iata.toLowerCase()}.meshmapper.net$endpoint'; From 40015830084e16f09da6d398ce37133962b7bec8 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Wed, 18 Feb 2026 23:22:38 -0500 Subject: [PATCH 10/57] ### New Features - Automatic map tile refresh after successful data upload, so new coverage appears on the map within the app near real-time - Deterministic 5-second upload timer for TX and discovery pings, replacing the old batch system that could take up to 20 seconds ### Bug Fixes - Fixed tile refresh race condition that caused half-rendered tiles and ghost tiles at certain zoom levels - Fixed Light (OSM) and Satellite (ArcGIS) tiles failing to load at low zoom on iOS retina displays ### Improvements - Faster ping cycle with reduced listen window (7s to 5s) for TX echo, discovery response, and auto-ping cooldown - Map zoom range adjusted to 3-17 - Updated repeater endpoint from /repeaters.json to /get_repeaters.php - Immediate upload on disconnect with no wait period --- lib/models/api_queue_item.dart | 4 +- lib/providers/app_state_provider.dart | 22 ++++++- lib/services/api_queue_service.dart | 59 +++++++------------ lib/services/meshcore/disc_tracker.dart | 2 +- lib/services/meshcore/tx_tracker.dart | 4 +- lib/services/meshcore/unified_rx_handler.dart | 2 +- lib/services/ping_service.dart | 39 ++++++------ lib/widgets/map_widget.dart | 28 +++++++-- 8 files changed, 86 insertions(+), 74 deletions(-) diff --git a/lib/models/api_queue_item.dart b/lib/models/api_queue_item.dart index f2e4bcd..67714bb 100644 --- a/lib/models/api_queue_item.dart +++ b/lib/models/api_queue_item.dart @@ -44,7 +44,7 @@ class ApiQueueItem extends HiveObject { final String heardRepeats; /// Earliest time this item can be uploaded (milliseconds since epoch) - /// TX items have 5-second delay; RX/DISC are immediate + /// All items are immediate; upload timing is controlled by flush timers @HiveField(13) final int canUploadAfter; @@ -81,7 +81,7 @@ class ApiQueueItem extends HiveObject { longitude: longitude, timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000), heardRepeats: heardRepeats, - canUploadAfter: DateTime.now().millisecondsSinceEpoch + 5000, // 5 seconds from now + canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate — flush timer controls upload timing externalAntenna: externalAntenna, noiseFloor: noiseFloor, ); diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 73e7af3..a85a298 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -203,6 +203,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { String? _maintenanceUrl; Timer? _maintenanceCheckTimer; + // Tile refresh after upload + int _overlayCacheBust = 0; + Timer? _tileRefreshTimer; + // Auth type from API response (API, Mesh, Manual) String? _authType; @@ -324,6 +328,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get isCheckingZone => _isCheckingZone; String? get zoneName => _currentZone?['name'] as String?; String? get zoneCode => _currentZone?['code'] as String?; + int get overlayCacheBust => _overlayCacheBust; int? get zoneSlotsAvailable => _currentZone?['slots_available'] as int?; int? get zoneSlotsMax => _currentZone?['slots_max'] as int?; String? get nearestZoneName => _nearestZone?['name'] as String?; @@ -478,6 +483,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ); debugLog('[APP] Upload success: +$uploadedCount items (total: ${_pingStats.successfulUploads})'); notifyListeners(); + + // Schedule overlay tile refresh after server has time to regenerate tiles + // Cache buster change + notifyListeners triggers flutter_map's reloadImages() + // which updates tile URLs in-place and refetches cleanly + _tileRefreshTimer?.cancel(); + _tileRefreshTimer = Timer(const Duration(seconds: 5), () { + _overlayCacheBust = DateTime.now().millisecondsSinceEpoch; + debugLog('[MAP] Refreshing overlay tiles'); + notifyListeners(); + }); }; // Initialize offline session service @@ -2161,11 +2176,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _autoPingEnabled = false; - // Start 7-second shared cooldown for TX modes (Active/Hybrid), not Passive Mode + // Start 5-second shared cooldown for TX modes (Active/Hybrid), not Passive Mode // Passive Mode is listening only, no cooldown needed if (isTxMode) { - _cooldownTimer.start(7000); - debugLog('[${mode.name.toUpperCase()} MODE] Shared cooldown started (7s) - blocks TX Ping and TX modes'); + _cooldownTimer.start(5000); + debugLog('[${mode.name.toUpperCase()} MODE] Shared cooldown started (5s) - blocks TX Ping and TX modes'); } else { debugLog('[PASSIVE MODE] Stopped - no cooldown (listen-only mode)'); } @@ -4106,6 +4121,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _zoneCheckCountdownTimer?.cancel(); _reconnectTimer?.cancel(); _reconnectTimeoutTimer?.cancel(); + _tileRefreshTimer?.cancel(); _unifiedRxHandler?.dispose(); _meshCoreConnection?.dispose(); _pingService?.dispose(); diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index d55fdca..b2f708b 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -25,6 +25,7 @@ class ApiQueueService { final ApiService _apiService; Box? _box; Timer? _batchTimer; + Timer? _pingFlushTimer; bool _isUploading = false; bool _isRecovering = false; @@ -238,7 +239,12 @@ class ApiQueueService { await _safeWrite((box) => box.add(item)); debugLog('[API QUEUE] TX enqueued: $heardRepeats (queue size: $queueSize)'); onQueueUpdated?.call(queueSize); - _checkBatchUpload(); + _pingFlushTimer?.cancel(); + _pingFlushTimer = Timer(const Duration(seconds: 5), () { + debugLog('[API QUEUE] Ping flush timer fired'); + _flushRxBuffer(); + _uploadBatch(); + }); } /// Enqueue an RX observation @@ -319,7 +325,12 @@ class ApiQueueService { await _safeWrite((box) => box.add(item)); debugLog('[API QUEUE] DISC enqueued: $repeaterId ($nodeType) at $latitude, $longitude (queue size: $queueSize)'); onQueueUpdated?.call(queueSize); - _checkBatchUpload(); + _pingFlushTimer?.cancel(); + _pingFlushTimer = Timer(const Duration(seconds: 5), () { + debugLog('[API QUEUE] Ping flush timer fired'); + _flushRxBuffer(); + _uploadBatch(); + }); } // Guard to prevent concurrent RX buffer flushes @@ -373,12 +384,6 @@ class ApiQueueService { }); } - void _checkBatchUpload() { - if (queueSize >= _batchSize) { - _uploadBatch(); - } - } - /// Manually flush queue (called by TX-triggered flush timer) Future flushQueue() async { await _flushRxBuffer(); @@ -472,38 +477,11 @@ class ApiQueueService { await _uploadBatch(); } - /// Force upload after waiting for any TX items in hold period + /// Force upload all queued items immediately /// Used during BLE disconnect to ensure all data is uploaded before session release Future forceUploadWithHoldWait() async { + _pingFlushTimer?.cancel(); await _flushRxBuffer(); - - // Check if any TX items are still in hold period - try { - if (_box != null && _box!.isNotEmpty) { - final now = DateTime.now().millisecondsSinceEpoch; - int maxWaitMs = 0; - - for (final item in _box!.values) { - if (item.type == 'TX' && !item.isUploadEligible) { - final waitMs = item.canUploadAfter - now; - if (waitMs > maxWaitMs) { - maxWaitMs = waitMs; - } - } - } - - if (maxWaitMs > 0) { - // Cap wait time at 6 seconds (slightly more than 5s hold period) - final cappedWaitMs = maxWaitMs.clamp(0, 6000); - debugLog('[API QUEUE] Waiting ${cappedWaitMs}ms for TX hold period to expire'); - await Future.delayed(Duration(milliseconds: cappedWaitMs)); - } - } - } catch (e) { - debugError('[API QUEUE] Failed to check hold period: $e - skipping wait'); - await _recoverBox(); - } - await _uploadBatch(); } @@ -518,10 +496,12 @@ class ApiQueueService { /// Called when device disconnects to ensure no stale pings remain /// Also stops the batch timer to prevent upload attempts without a session Future clearOnDisconnect() async { - // Stop the batch timer to prevent upload attempts without session + // Stop timers to prevent upload attempts without session _batchTimer?.cancel(); _batchTimer = null; - debugLog('[API QUEUE] Batch timer stopped on disconnect'); + _pingFlushTimer?.cancel(); + _pingFlushTimer = null; + debugLog('[API QUEUE] Timers stopped on disconnect'); final count = queueSize + _rxBuffer.length; if (count > 0) { @@ -575,6 +555,7 @@ class ApiQueueService { /// Dispose of resources void dispose() { _batchTimer?.cancel(); + _pingFlushTimer?.cancel(); _box?.close(); } } diff --git a/lib/services/meshcore/disc_tracker.dart b/lib/services/meshcore/disc_tracker.dart index c9c1c5c..3013013 100644 --- a/lib/services/meshcore/disc_tracker.dart +++ b/lib/services/meshcore/disc_tracker.dart @@ -42,7 +42,7 @@ class DiscTracker { /// @param windowDuration - How long to listen (default 7 seconds) void startTracking({ required Uint8List tag, - Duration windowDuration = const Duration(seconds: 7), + Duration windowDuration = const Duration(seconds: 5), }) { debugLog('[DISC] Starting discovery tracking'); debugLog('[DISC] Tag: ${tag.map((b) => b.toRadixString(16).padLeft(2, '0')).join('')}'); diff --git a/lib/services/meshcore/tx_tracker.dart b/lib/services/meshcore/tx_tracker.dart index 41a5a6b..925f199 100644 --- a/lib/services/meshcore/tx_tracker.dart +++ b/lib/services/meshcore/tx_tracker.dart @@ -7,7 +7,7 @@ import 'crypto_service.dart'; import 'packet_metadata.dart'; import 'packet_validator.dart'; -/// TX echo tracker for repeater detection during 7-second window +/// TX echo tracker for repeater detection during 5-second window /// Reference: handleTxLogging() in wardrive.js (lines 3561-3710) class TxTracker { bool isListening = false; @@ -54,7 +54,7 @@ class TxTracker { required int channelIdx, required int channelHash, required Uint8List channelKey, - Duration windowDuration = const Duration(seconds: 7), + Duration windowDuration = const Duration(seconds: 5), }) { debugLog('[TX LOG] Starting echo tracking'); debugLog('[TX LOG] Payload: "$payload"'); diff --git a/lib/services/meshcore/unified_rx_handler.dart b/lib/services/meshcore/unified_rx_handler.dart index f78c962..a15730e 100644 --- a/lib/services/meshcore/unified_rx_handler.dart +++ b/lib/services/meshcore/unified_rx_handler.dart @@ -73,7 +73,7 @@ class UnifiedRxHandler { 'header=0x${metadata.header.toRadixString(16)}, ' 'pathLength=${metadata.pathLength}'); - // Route to TX tracking if active (during 7s echo window) + // Route to TX tracking if active (during 5s echo window) if (txTracker.isListening) { debugLog('[UNIFIED RX] TX tracking active - checking for echo'); final wasEcho = await txTracker.handlePacket(metadata); diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 872eebd..1b920a2 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -22,7 +22,7 @@ import 'wakelock_service.dart'; /// 1. Validate GPS lock, 25m min distance (zone validation handled server-side) /// 2. Start TxTracker to monitor for repeater echoes /// 3. Send @[MapperBot] LAT, LON [POWERw] to #wardriving channel -/// 4. Start 6-second RX listening window (matches JS RX_LOG_LISTEN_WINDOW_MS) +/// 4. Start 5-second RX listening window /// 5. Post to API queue with type "TX" /// /// RX Flow (via TxTracker): @@ -33,16 +33,16 @@ import 'wakelock_service.dart'; /// /// Discovery Flow (Passive Mode only): /// 1. In Passive Mode, send discovery request instead of TX ping -/// 2. Start 7-second listening window via DiscTracker +/// 2. Start 5-second listening window via DiscTracker /// 3. Collect discovery responses (0x8E packets) /// 4. After window ends, create log entry and queue DISC API payloads class PingService { - /// RX listening window duration (7 seconds - matches cooldown duration) - static const Duration _rxListeningWindow = Duration(seconds: 7); - /// Cooldown period between pings (7 seconds - matches JS COOLDOWN_MS = 7000) - static const Duration _autoPingCooldown = Duration(seconds: 7); - /// Discovery listening window duration (7 seconds) - static const Duration _discoveryListeningWindow = Duration(seconds: 7); + /// RX listening window duration (5 seconds - matches cooldown duration) + static const Duration _rxListeningWindow = Duration(seconds: 5); + /// Cooldown period between pings (5 seconds) + static const Duration _autoPingCooldown = Duration(seconds: 5); + /// Discovery listening window duration (5 seconds) + static const Duration _discoveryListeningWindow = Duration(seconds: 5); /// Discovery request interval (30 seconds - repeaters only respond 4 times per 2 minutes) static const Duration _discoveryInterval = Duration(seconds: 30); /// Cooldown period between manual pings (15 seconds) @@ -269,7 +269,7 @@ class PingService { return PingValidation.tooCloseToLastPing; } - // Check cooldown (7 seconds between pings) + // Check cooldown (5 seconds between pings) final lastTx = _lastTxTime; if (lastTx != null) { final elapsed = DateTime.now().difference(lastTx); @@ -378,7 +378,7 @@ class PingService { // NOTE: Skip distance check (tooCloseToLastPing) intentionally // Auto mode handles this by setting skipReason='too close' and scheduling next ping - // Check cooldown (7 seconds between pings) + // Check cooldown (5 seconds between pings) final lastTx = _lastTxTime; if (lastTx != null) { final elapsed = DateTime.now().difference(lastTx); @@ -451,7 +451,7 @@ class PingService { return false; } } else { - // Auto ping: 7-second cooldown, 25m distance check + // Auto ping: 5-second cooldown, 25m distance check // This fixes a race condition where disabling Active Mode during cooldown // could still trigger an auto-ping from a late RX window timer callback if (isInCooldown()) { @@ -586,7 +586,7 @@ class PingService { // Manual ping: 15-second cooldown, no distance check _manualPingCooldownTimer.start(_manualPingCooldown.inMilliseconds); } else { - // Auto ping: 7-second cooldown + // Auto ping: 5-second cooldown _cooldownTimer.start(_autoPingCooldown.inMilliseconds); } @@ -614,14 +614,13 @@ class PingService { } } - /// Start the 6-second RX listening window after TX + /// Start the 5-second RX listening window after TX /// Note: TxTracker handles the actual echo tracking, we just manage the countdown UI - /// Reference: RX_LOG_LISTEN_WINDOW_MS = 6000 in wardrive.js void _startRxListeningWindow(Position txPosition) { // Cancel previous timer _rxWindowTimer?.cancel(); - // Start RX window countdown display (6 seconds - matches JS RX_LOG_LISTEN_WINDOW_MS) + // Start RX window countdown display (5 seconds) _rxWindowCountdown.start(_rxListeningWindow.inMilliseconds); // Set timer for window end @@ -1073,7 +1072,7 @@ class PingService { windowDuration: _discoveryListeningWindow, ); - // Start discovery window countdown display (7 seconds) + // Start discovery window countdown display (5 seconds) _discoveryWindowCountdown.start(_discoveryListeningWindow.inMilliseconds); // Clear pingInProgress now that discovery window is active @@ -1180,8 +1179,8 @@ class PingService { _autoTimer = null; // Subtract listening window so interval is measured start-to-start - // At 15s: wait = 15000 - 7000 = 8000ms. Clamp to min 1s. - final listenMs = _rxListeningWindow.inMilliseconds; // 7000 + // At 15s: wait = 15000 - 5000 = 10000ms. Clamp to min 1s. + final listenMs = _rxListeningWindow.inMilliseconds; // 5000 final waitMs = (_autoPingIntervalMs - listenMs).clamp(1000, _autoPingIntervalMs); final isNextDisc = _nextPingIsDiscovery; @@ -1264,7 +1263,7 @@ enum PingValidation { /// Too close to last ping (< 25m) tooCloseToLastPing, - /// Cooldown period active (< 7s since last ping) + /// Cooldown period active (< 5s since last ping) cooldownActive, /// Manual ping cooldown period active (< 15s since last manual ping) @@ -1296,7 +1295,7 @@ extension PingValidationExtension on PingValidation { case PingValidation.tooCloseToLastPing: return 'Move 25m before next ping'; case PingValidation.cooldownActive: - return 'Wait 7 seconds between pings'; + return 'Wait 5 seconds between pings'; case PingValidation.manualCooldownActive: return 'Wait 15 seconds between manual pings'; case PingValidation.txNotAllowed: diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index f050615..0940ae0 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -80,6 +80,18 @@ extension MapStyleExtension on MapStyle { return null; // ArcGIS doesn't use subdomains } } + + /// Whether this style supports retina tiles via {r} placeholder + bool get supportsRetina { + switch (this) { + case MapStyle.dark: + return true; // Carto supports @2x via {r} + case MapStyle.light: + return false; // OSM has no retina support + case MapStyle.satellite: + return false; // ArcGIS has no retina support + } + } } /// Custom tile provider that silently handles HTTP errors (404, 503, etc.) @@ -616,7 +628,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { initialCenter: center, initialZoom: _defaultZoom, minZoom: 3, - maxZoom: 18, + maxZoom: 17, interactionOptions: InteractionOptions( flags: _rotationLocked ? InteractiveFlag.all & ~InteractiveFlag.rotate @@ -639,9 +651,9 @@ class _MapWidgetState extends State with TickerProviderStateMixin { urlTemplate: mapStyle.urlTemplate, subdomains: mapStyle.subdomains ?? const [], userAgentPackageName: 'com.meshmapper.app', - maxZoom: 19, - retinaMode: RetinaMode.isHighDensity(context), // Enable high-res tiles on retina displays - tileProvider: SilentCancellableNetworkTileProvider(), // Silently handles tile errors + maxZoom: 17, + retinaMode: mapStyle.supportsRetina && RetinaMode.isHighDensity(context), + tileProvider: SilentCancellableNetworkTileProvider(), ); }, ), @@ -649,9 +661,13 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // MeshMapper coverage overlay (only when zone code available and overlay enabled) if (appState.zoneCode != null && _showMeshMapperOverlay) TileLayer( - urlTemplate: 'https://${appState.zoneCode!.toLowerCase()}.meshmapper.net/tiles.php?x={x}&y={y}&z={z}', + urlTemplate: 'https://${appState.zoneCode!.toLowerCase()}.meshmapper.net/tiles.php?x={x}&y={y}&z={z}&t=${appState.overlayCacheBust}', userAgentPackageName: 'com.meshmapper.app', - maxZoom: 19, + minZoom: 3, + maxZoom: 17, + tileDisplay: const TileDisplay.fadeIn( + reloadStartOpacity: 1.0, // Keep old tile visible until new one loads + ), tileProvider: SilentCancellableNetworkTileProvider(), ), From 9fe6acf0cfb0340a751581c0c89040f43397cefb Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Thu, 19 Feb 2026 21:38:39 -0500 Subject: [PATCH 11/57] Regional Flood Scoping: TX pings(Active Mode) are now scoped to your region's flood zone. Regional Admins set a scope in the admin panel, so only repeaters in your region forward wardriving pings. Discovery pings are unaffected. If no scope is assigned, pings flood globally as before. --- lib/providers/app_state_provider.dart | 33 ++++++++++++++++++- lib/screens/connection_screen.dart | 2 ++ lib/services/api_service.dart | 14 ++++++++ lib/services/meshcore/connection.dart | 18 ++++++++++ lib/services/meshcore/crypto_service.dart | 14 ++++++++ lib/services/meshcore/protocol_constants.dart | 1 + lib/widgets/regional_config_card.dart | 12 +++++++ 7 files changed, 93 insertions(+), 1 deletion(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index a85a298..cf17c8d 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -29,6 +29,7 @@ import '../services/gps_service.dart'; import '../services/gps_simulator_service.dart'; import '../services/meshcore/channel_service.dart'; import '../services/meshcore/connection.dart'; +import '../services/meshcore/crypto_service.dart'; import '../services/meshcore/packet_validator.dart' show PacketValidator, ChannelInfo; import '../services/meshcore/rx_logger.dart'; import '../services/meshcore/tx_tracker.dart'; @@ -240,6 +241,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Regional channels from API (for UI display) List _regionalChannels = []; + // Regional scope from API (for UI display and flood filtering) + String? _scope; + // Noise floor session tracking (for graph feature) NoiseFloorSession? _currentNoiseFloorSession; List _storedNoiseFloorSessions = []; @@ -365,6 +369,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Regional channels getter (for UI) List get regionalChannels => List.unmodifiable(_regionalChannels); + // Regional scope getter (for UI) + String? get scope => _scope; + // Noise floor session getters NoiseFloorSession? get currentNoiseFloorSession => _currentNoiseFloorSession; List get storedNoiseFloorSessions => @@ -1076,6 +1083,22 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { '${allowedChannelsData.values.map((c) => c.channelName).join(', ')}'); } + // Set flood scope from API response (regional TX filtering) + // "*" = wildcard/global → no scope (unscoped flood, same as before) + // Any other value (e.g., "ottawa") → derive TransportKey and set scope + final apiScopes = _apiService.scopes; + if (apiScopes.isNotEmpty && apiScopes.first != '*') { + final scopeName = apiScopes.first; + _scope = scopeName.startsWith('#') ? scopeName : '#$scopeName'; + final scopeKey = CryptoService.deriveScopeKey(scopeName); + debugLog('[CONN] Setting flood scope: $scopeName'); + await _meshCoreConnection!.setFloodScope(scopeKey); + debugLog('[CONN] Flood scope set successfully'); + } else { + _scope = null; + debugLog('[CONN] No regional scope — using unscoped flood'); + } + // Create ping service with wakelock (create new instance per connection) _pingService = PingService( gpsService: _gpsService, @@ -2002,6 +2025,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _originalDeviceName = null; } + // Clear flood scope before disconnect (safety — BLE disconnect resets radio state anyway) + try { + await _meshCoreConnection?.clearFloodScope(); + } catch (e) { + debugLog('[CONN] Failed to clear flood scope: $e'); + } + // Delete wardriving channel FIRST, while BLE connection is still active // This prevents "GATT Server is disconnected" errors await _meshCoreConnection?.deleteWardrivingChannelEarly(); @@ -2040,9 +2070,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _currentBatteryPercent = null; _authType = null; - // Clear regional channels (keeps only Public) + // Clear regional channels (keeps only Public) and scope ChannelService.clearRegionalChannels(); _regionalChannels = []; + _scope = null; // Clear discovered devices so user must scan fresh _discoveredDevices = []; diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index c0a4825..9be5eed 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -369,6 +369,7 @@ class _ConnectionScreenState extends State with WidgetsBinding zoneName: appState.offlineMode ? null : appState.zoneName, zoneCode: appState.offlineMode ? null : appState.zoneCode, channels: appState.offlineMode ? [] : appState.regionalChannels, + scope: appState.offlineMode ? null : appState.scope, isOfflineMode: appState.offlineMode, ), ], @@ -396,6 +397,7 @@ class _ConnectionScreenState extends State with WidgetsBinding zoneName: appState.offlineMode ? null : appState.zoneName, zoneCode: appState.offlineMode ? null : appState.zoneCode, channels: appState.offlineMode ? [] : appState.regionalChannels, + scope: appState.offlineMode ? null : appState.scope, isOfflineMode: appState.offlineMode, ), ], diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 885e005..9c32895 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -40,6 +40,7 @@ class ApiService { Timer? _heartbeatTimer; Function? _onSessionExpiring; List _channels = []; + List _scopes = []; /// Callback to get current GPS coordinates for heartbeat /// Returns (lat, lon) or null if GPS is not available @@ -48,6 +49,9 @@ class ApiService { /// Regional channels from auth response (e.g., ['public', 'ottawa', 'testing']) List get channels => List.unmodifiable(_channels); + /// Regional scopes from auth response (e.g., ['ottawa']) + List get scopes => List.unmodifiable(_scopes); + ApiService({http.Client? client}) : _client = client ?? http.Client(); /// Sanitize payload by removing sensitive fields for logging @@ -302,6 +306,15 @@ class ApiService { _channels = []; } + // Parse scopes array from auth response + final scopesData = data['scopes']; + if (scopesData is List && scopesData.isNotEmpty) { + _scopes = scopesData.cast().toList(); + debugLog('[API] Regional scopes: $_scopes'); + } else { + _scopes = []; + } + // Note: Heartbeat is enabled by AppStateProvider when auto mode starts // (not on initial auth, since heartbeat is only for auto mode) } else if (reason == 'disconnect') { @@ -600,6 +613,7 @@ class ApiService { _rxAllowed = false; _sessionExpiresAt = null; _channels = []; + _scopes = []; _heartbeatTimer?.cancel(); _heartbeatTimer = null; debugLog('[API] Session cleared'); diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index acf90d4..339e406 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -779,6 +779,24 @@ class MeshCoreConnection { await _sendToRadio(data); } + /// Set flood scope for regional packet filtering + /// TransportKey is 16-byte SHA-256 derived key from scope name + Future setFloodScope(Uint8List transportKey) async { + final data = BufferWriter(); + data.writeByte(CommandCodes.setFloodScope); + data.writeByte(0); // reserved byte + data.writeBytes(transportKey); // 16-byte key + await _sendToRadio(data); + } + + /// Clear flood scope (return to unscoped global flood) + Future clearFloodScope() async { + final data = BufferWriter(); + data.writeByte(CommandCodes.setFloodScope); + data.writeByte(0); // reserved byte — no key means clear + await _sendToRadio(data); + } + /// Delete channel by setting it to empty Future deleteChannel(int channelIdx) async { await setChannel(channelIdx, '', Uint8List(16)); diff --git a/lib/services/meshcore/crypto_service.dart b/lib/services/meshcore/crypto_service.dart index cf736dd..30da886 100644 --- a/lib/services/meshcore/crypto_service.dart +++ b/lib/services/meshcore/crypto_service.dart @@ -55,6 +55,20 @@ class CryptoService { return channelKey; } + /// Derive a 16-byte TransportKey from a scope/region name + /// Same algorithm as channel key derivation: SHA-256(name)[0:16] + /// API returns names without '#' prefix (e.g., "ottawa") — we prepend it + /// to match MeshCore's implicit hashtag region convention + static Uint8List deriveScopeKey(String scopeName) { + final name = scopeName.startsWith('#') ? scopeName : '#$scopeName'; + final normalizedName = name.toLowerCase(); + final bytes = utf8.encode(normalizedName); + final digest = sha256.convert(bytes); + final scopeKey = Uint8List.fromList(digest.bytes.sublist(0, 16)); + debugLog('[CRYPTO] Scope key derived for "$normalizedName" (${scopeKey.length} bytes)'); + return scopeKey; + } + /// Get channel key for any channel (handles both Public and hashtag channels) /// /// @param channelName - Channel name (e.g., "Public", "#wardriving", "#testing") diff --git a/lib/services/meshcore/protocol_constants.dart b/lib/services/meshcore/protocol_constants.dart index 537d229..56f7f6c 100644 --- a/lib/services/meshcore/protocol_constants.dart +++ b/lib/services/meshcore/protocol_constants.dart @@ -66,6 +66,7 @@ class CommandCodes { static const int sendControlData = 55; // 0x37 - CMD_SEND_CONTROL_DATA (discovery) static const int setOtherParams = 38; static const int sendTelemetryReq = 39; + static const int setFloodScope = 54; // 0x36 - CMD_SET_FLOOD_SCOPE static const int getStats = 56; // 0x38 static const int sendBinaryReq = 50; } diff --git a/lib/widgets/regional_config_card.dart b/lib/widgets/regional_config_card.dart index 4c50483..bdc9b31 100644 --- a/lib/widgets/regional_config_card.dart +++ b/lib/widgets/regional_config_card.dart @@ -6,6 +6,7 @@ class RegionalConfigCard extends StatelessWidget { final String? zoneName; final String? zoneCode; final List channels; + final String? scope; final bool isOfflineMode; const RegionalConfigCard({ @@ -13,6 +14,7 @@ class RegionalConfigCard extends StatelessWidget { this.zoneName, this.zoneCode, this.channels = const [], + this.scope, this.isOfflineMode = false, }); @@ -72,6 +74,16 @@ class RegionalConfigCard extends StatelessWidget { isOffline: isOfflineMode), const SizedBox(height: 12), + // Scope + _buildInfoRow( + context, + Icons.filter_alt, + 'Scope', + isOfflineMode ? '-' : (scope ?? 'Global'), + isOffline: isOfflineMode, + ), + const SizedBox(height: 12), + // Channels header _buildInfoRow(context, Icons.tag, 'RX Channels', null), const SizedBox(height: 8), From fa17d597befd001738edb0d7f2b570ac69bd0a98 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Fri, 20 Feb 2026 21:55:32 -0500 Subject: [PATCH 12/57] New Features Regional admins can now enforce hybrid mode per-zone via the API; when enabled, hybrid mode is automatically activated and the toggle is locked on the Settings screen with a "Forced Enabled by Regional Admin" label Regional admins can set a minimum auto-ping interval per-zone; interval options below the minimum are greyed out in Settings with a "Disabled by Regional Admin" label If a user's saved interval falls below the admin-configured minimum, it is automatically bumped up on connect --- lib/providers/app_state_provider.dart | 14 +++++++ lib/screens/settings_screen.dart | 57 +++++++++++++++++++++------ lib/services/api_service.dart | 25 ++++++++++++ 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index cf17c8d..d7995b7 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -390,6 +390,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get rxAllowed => _apiService.rxAllowed; bool get hasApiSession => _apiService.hasSession; bool get isApiRxOnlyMode => hasApiSession && !txAllowed && rxAllowed; + bool get enforceHybrid => _apiService.enforceHybrid; + int get minModeInterval => _apiService.minModeInterval; // Offline mode bool get offlineMode => _preferences.offlineMode; @@ -1099,6 +1101,18 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[CONN] No regional scope — using unscoped flood'); } + // Enforce hybrid mode if required by regional admin + if (_apiService.enforceHybrid && !_preferences.hybridModeEnabled) { + _preferences = _preferences.copyWith(hybridModeEnabled: true); + debugLog('[CONN] Hybrid mode force-enabled by regional admin'); + } + + // Enforce minimum auto-ping interval if required by regional admin + if (_preferences.autoPingInterval < _apiService.minModeInterval) { + _preferences = _preferences.copyWith(autoPingInterval: _apiService.minModeInterval); + debugLog('[CONN] Auto-ping interval bumped to ${_apiService.minModeInterval}s by regional admin'); + } + // Create ping service with wakelock (create new instance per connection) _pingService = PingService( gpsService: _gpsService, diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 07d8078..f580db6 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -242,9 +242,14 @@ class _SettingsScreenState extends State { ), ], ), - subtitle: const Text('Combines Active and Passive modes'), - value: prefs.hybridModeEnabled, - onChanged: isAutoMode ? null : (value) { + subtitle: appState.enforceHybrid + ? const Text( + 'Forced Enabled by Regional Admin', + style: TextStyle(color: Colors.amber), + ) + : const Text('Combines Active and Passive modes'), + value: appState.enforceHybrid ? true : prefs.hybridModeEnabled, + onChanged: (isAutoMode || appState.enforceHybrid) ? null : (value) { appState.updatePreferences(prefs.copyWith(hybridModeEnabled: value)); }, ), @@ -1083,7 +1088,16 @@ class _SettingsScreenState extends State { } void _showIntervalSelector(BuildContext context, AppStateProvider appState) { - final currentInterval = appState.preferences.autoPingInterval; + final minInterval = appState.minModeInterval; + var currentInterval = appState.preferences.autoPingInterval; + + // Auto-bump if current interval is below the admin minimum + if (currentInterval < minInterval) { + currentInterval = minInterval; + appState.updatePreferences( + appState.preferences.copyWith(autoPingInterval: minInterval), + ); + } showDialog( context: context, @@ -1102,18 +1116,37 @@ class _SettingsScreenState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: AutoPingInterval.values.map((interval) { - final isSelected = interval == currentInterval; + final isDisabled = interval < minInterval; + + String description; + if (interval == 15) { + description = 'Fast (More coverage, causes more mesh load)'; + } else if (interval == 30) { + description = 'Normal (Balanced coverage and mesh load)'; + } else { + description = 'Slow (Less coverage, little mesh load)'; + } - return RadioListTile( + final tile = RadioListTile( title: Text('$interval seconds'), - subtitle: Text(interval == 15 - ? 'Fast (More coverage, causes more mesh load)' - : interval == 30 - ? 'Normal (Balanced coverage and mesh load)' - : 'Slow (Less coverage, little mesh load)'), + subtitle: isDisabled + ? const Text( + 'Disabled by Regional Admin', + style: TextStyle(color: Colors.amber), + ) + : Text(description), value: interval, - selected: isSelected, ); + + if (isDisabled) { + return IgnorePointer( + child: Opacity( + opacity: 0.5, + child: tile, + ), + ); + } + return tile; }).toList(), ), ), diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 9c32895..6b5b6be 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -41,6 +41,8 @@ class ApiService { Function? _onSessionExpiring; List _channels = []; List _scopes = []; + bool _enforceHybrid = false; + int _minModeInterval = 15; /// Callback to get current GPS coordinates for heartbeat /// Returns (lat, lon) or null if GPS is not available @@ -52,6 +54,12 @@ class ApiService { /// Regional scopes from auth response (e.g., ['ottawa']) List get scopes => List.unmodifiable(_scopes); + /// Whether hybrid mode is enforced by regional admin + bool get enforceHybrid => _enforceHybrid; + + /// Minimum auto-ping interval enforced by regional admin (seconds) + int get minModeInterval => _minModeInterval; + ApiService({http.Client? client}) : _client = client ?? http.Client(); /// Sanitize payload by removing sensitive fields for logging @@ -315,6 +323,21 @@ class ApiService { _scopes = []; } + // Parse enforce_hybrid flag from auth response + _enforceHybrid = data['enforce_hybrid'] == true; + if (_enforceHybrid) { + debugLog('[API] Regional admin enforces hybrid mode'); + } + + // Parse min_mode_interval from auth response + final minInterval = data['min_mode_interval']; + if (minInterval is int && minInterval > 0) { + _minModeInterval = minInterval; + debugLog('[API] Regional admin min interval: ${_minModeInterval}s'); + } else { + _minModeInterval = 15; + } + // Note: Heartbeat is enabled by AppStateProvider when auto mode starts // (not on initial auth, since heartbeat is only for auto mode) } else if (reason == 'disconnect') { @@ -614,6 +637,8 @@ class ApiService { _sessionExpiresAt = null; _channels = []; _scopes = []; + _enforceHybrid = false; + _minModeInterval = 15; _heartbeatTimer?.cancel(); _heartbeatTimer = null; debugLog('[API] Session cleared'); From 48240725848e7f2dd576e175f755ed9a68a7ae7d Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Fri, 20 Feb 2026 22:37:15 -0500 Subject: [PATCH 13/57] ### Improvements - Admin-enforced settings now include reworded messaging with a brief explanation of why the constraint benefits the mesh --- lib/screens/settings_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index f580db6..4337144 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -244,7 +244,7 @@ class _SettingsScreenState extends State { ), subtitle: appState.enforceHybrid ? const Text( - 'Forced Enabled by Regional Admin', + 'Set by Regional Admin — hybrid uses 50% fewer flood packets, improving mesh health.', style: TextStyle(color: Colors.amber), ) : const Text('Combines Active and Passive modes'), @@ -1131,7 +1131,7 @@ class _SettingsScreenState extends State { title: Text('$interval seconds'), subtitle: isDisabled ? const Text( - 'Disabled by Regional Admin', + 'Set by Regional Admin — slower intervals reduce congestion in your region', style: TextStyle(color: Colors.amber), ) : Text(description), From e399a21cedaa4efc588872d565d5b54fe8a7b259 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 21 Feb 2026 07:43:32 -0500 Subject: [PATCH 14/57] ## Bug Fixes - Fixed RX carpeater detection checking the wrong hop position. On RX packets, the carpeater is co-located with the wardriver so it only appears as the last hop (delivery repeater), not the first. The check now correctly evaluates the last hop. --- debug/47.34022, -122.22241.txt | 11914 +++++++++++++++++++++++++ lib/services/meshcore/rx_logger.dart | 24 +- 2 files changed, 11927 insertions(+), 11 deletions(-) create mode 100644 debug/47.34022, -122.22241.txt diff --git a/debug/47.34022, -122.22241.txt b/debug/47.34022, -122.22241.txt new file mode 100644 index 0000000..02810eb --- /dev/null +++ b/debug/47.34022, -122.22241.txt @@ -0,0 +1,11914 @@ +=== MeshMapper Debug Log Started: 2026-02-20T17:23:11.248704 === + +[2026-02-20T17:23:11.249183] LOG: [APP] MeshMapper starting... +[2026-02-20T17:23:11.268604] LOG: [APP] Hive initialized +[2026-02-20T17:23:11.270718] LOG: [APP] Initial theme mode: dark +[2026-02-20T17:23:11.270737] LOG: [APP] Noise floor session adapters registered +[2026-02-20T17:23:11.270739] LOG: [APP] Requesting permissions... +[2026-02-20T17:23:11.271203] LOG: [APP] Permission.notification: PermissionStatus.granted +[2026-02-20T17:23:11.271207] LOG: [APP] Permission.bluetoothScan: PermissionStatus.granted +[2026-02-20T17:23:11.271208] LOG: [APP] Permission.bluetoothConnect: PermissionStatus.granted +[2026-02-20T17:23:11.271209] LOG: [BACKGROUND] Checking for orphaned service from previous session +[2026-02-20T17:23:11.271212] LOG: [BACKGROUND] Initializing background service +[2026-02-20T17:23:11.271754] LOG: [BACKGROUND] Service unexpectedly running after configure(), stopping it +[2026-02-20T17:23:11.271762] LOG: [BACKGROUND] Background service initialized +[2026-02-20T17:23:11.271933] LOG: [INIT] AppStateProvider initialization starting... +[2026-02-20T17:23:11.271981] LOG: [INIT] Development build detected (APP-1771555184), auto-enabling debug logs +[2026-02-20T17:23:11.287313] LOG: [CHANNEL] Initializing Public channel only +[2026-02-20T17:23:11.287333] LOG: [CHANNEL] Public channel initialized (hash=17) +[2026-02-20T17:23:11.287335] LOG: [APP] Channel service initialized (Public channel only) +[2026-02-20T17:23:11.287336] LOG: [INIT] Initializing API queue service... +[2026-02-20T17:23:11.287337] LOG: [API QUEUE] init() starting... +[2026-02-20T17:23:11.287338] LOG: [API QUEUE] Checking adapter registration... +[2026-02-20T17:23:11.287339] LOG: [API QUEUE] Registering ApiQueueItemAdapter... +[2026-02-20T17:23:11.287342] LOG: [API QUEUE] Adapter check complete +[2026-02-20T17:23:11.287343] LOG: [API QUEUE] Opening Hive box "api_queue"... +[2026-02-20T17:23:11.287632] LOG: [DISCLOSURE] Already shown, skipping +[2026-02-20T17:23:11.427066] LOG: [API QUEUE] Hive box "api_queue" opened successfully +[2026-02-20T17:23:11.427082] LOG: [API QUEUE] Starting batch timer... +[2026-02-20T17:23:11.427084] LOG: [API QUEUE] init() complete +[2026-02-20T17:23:11.427086] LOG: [INIT] API queue service initialized +[2026-02-20T17:23:11.427101] LOG: [OFFLINE] Initialized with 0 stored sessions +[2026-02-20T17:23:11.446673] LOG: [HIVE] Opening typed box "noise_floor_sessions"... +[2026-02-20T17:23:11.462480] LOG: [HIVE] Typed box "noise_floor_sessions" opened successfully +[2026-02-20T17:23:11.462568] LOG: [GRAPH] Loaded 1 stored noise floor sessions +[2026-02-20T17:23:11.462571] LOG: [HIVE] Opening box "remembered_device"... +[2026-02-20T17:23:11.464016] LOG: [HIVE] Box "remembered_device" opened successfully +[2026-02-20T17:23:11.464134] LOG: [APP] Loaded remembered device: MeshCore-Cozmo +[2026-02-20T17:23:11.464138] LOG: [INIT] Loading preferences... +[2026-02-20T17:23:11.464140] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:11.464151] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:11.464159] LOG: [APP] Loaded preferences: interval=30s, ignoreCarpeater=true, ignoreRepeaterId=CC +[2026-02-20T17:23:11.464161] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:11.464163] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:11.464165] LOG: [APP] Loaded antenna preferences for 1 device(s) +[2026-02-20T17:23:11.464167] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:11.464169] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:11.464175] LOG: [GPS] Loaded last position: 47.3580211, -122.1619081 +[2026-02-20T17:23:11.464176] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:11.464178] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:11.464181] LOG: [APP] Loaded last connected device: Cozmo +[2026-02-20T17:23:11.464182] LOG: [INIT] Setting up Bluetooth adapter state listener... +[2026-02-20T17:23:11.464190] LOG: [INIT] Setting up BLE connection listener... +[2026-02-20T17:23:11.464192] LOG: [INIT] Setting up GPS status listener... +[2026-02-20T17:23:11.464195] LOG: [INIT] Initial GPS status: GpsStatus.permissionDenied +[2026-02-20T17:23:11.464196] LOG: [INIT] Setting up GPS position listener... +[2026-02-20T17:23:11.464198] LOG: [INIT] GPS position listener attached to stream +[2026-02-20T17:23:11.464199] LOG: [INIT] Starting GPS service... +[2026-02-20T17:23:11.464201] LOG: [GPS] startWatching() called, current status: GpsStatus.permissionDenied +[2026-02-20T17:23:11.482217] LOG: [MAP] Initial zoom to last known position +[2026-02-20T17:23:11.489490] LOG: [BLE] Adapter state changed: BluetoothAdapterState.on +[2026-02-20T17:23:11.497466] LOG: [GPS] Location services check: enabled=true +[2026-02-20T17:23:11.497826] LOG: [GPS] Permission check: LocationPermission.whileInUse (hasPermission=true) +[2026-02-20T17:23:11.497829] LOG: [GPS] Starting position stream listener... +[2026-02-20T17:23:11.497832] LOG: [GPS SERVICE] Status update: GpsStatus.permissionDenied → GpsStatus.searching +[2026-02-20T17:23:11.497856] LOG: [GPS] Requesting initial position (15s timeout)... +[2026-02-20T17:23:11.497906] LOG: [GPS] Status changed: GpsStatus.permissionDenied → GpsStatus.searching +[2026-02-20T17:23:13.109098] LOG: [GPS SERVICE] Position stream fired: lat=47.33787, lon=-122.22475, accuracy=11.1m +[2026-02-20T17:23:13.109121] LOG: [GPS SERVICE] Status update: GpsStatus.searching → GpsStatus.locked +[2026-02-20T17:23:13.109128] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:13.109134] LOG: [GEOFENCE] First GPS lock, triggering zone check +[2026-02-20T17:23:13.109135] LOG: [GEOFENCE] checkZoneStatus() called +[2026-02-20T17:23:13.109136] LOG: [GEOFENCE] Pre-check state: inZone=null, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.searching +[2026-02-20T17:23:13.109138] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=null) +[2026-02-20T17:23:13.109140] LOG: [GEOFENCE] Making API call to check zone at 47.33787, -122.22475 (accuracy: 11.1m) +[2026-02-20T17:23:13.109265] LOG: [GPS] Status changed: GpsStatus.searching → GpsStatus.locked +[2026-02-20T17:23:13.109267] LOG: [GPS] GPS lock acquired - zone check should trigger on first position +[2026-02-20T17:23:13.109269] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:13.109798] LOG: [GPS] Initial position acquired: 47.33787, -122.22475 (accuracy: 11.1m) +[2026-02-20T17:23:13.109802] LOG: [INIT] GPS service started, status: GpsStatus.locked +[2026-02-20T17:23:13.109803] LOG: [AUDIO] Initializing audio service +[2026-02-20T17:23:13.109804] LOG: [AUDIO] Opening Hive box "audio_preferences"... +[2026-02-20T17:23:13.110840] LOG: [AUDIO] Hive box "audio_preferences" opened successfully +[2026-02-20T17:23:13.110849] LOG: [AUDIO] No saved preference, using default: false +[2026-02-20T17:23:13.110983] LOG: [AUDIO] Audio session configured for notification mixing +[2026-02-20T17:23:13.125784] LOG: [MAP] Initial zoom to GPS position (with panel offset) +[2026-02-20T17:23:13.222236] LOG: [AUDIO] Audio service initialized, enabled=false +[2026-02-20T17:23:13.222294] LOG: [INIT] AppStateProvider initialization complete +[2026-02-20T17:23:13.222299] LOG: [INIT] Final init state: gpsStatus=GpsStatus.locked, inZone=null, isCheckingZone=true, hasPosition=true, offlineMode=false +[2026-02-20T17:23:14.020661] LOG: [API] POST /wardrive-api.php/status +[2026-02-20T17:23:14.020686] LOG: [API] Request: {"lat":47.3378661,"lng":-122.2247461,"accuracy_m":11.083000183105469,"ver":"APP-1771555184","timestamp":1771636993} +[2026-02-20T17:23:14.020692] LOG: [API] Response (200) in 0.91s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":11,"slots_max":15}} +[2026-02-20T17:23:14.020697] LOG: [GEOFENCE] API response received: valid +[2026-02-20T17:23:14.020703] LOG: [GEOFENCE] In zone: Seattle, US (SEA) +[2026-02-20T17:23:14.020705] LOG: [MAP] Fetching repeaters for zone: SEA +[2026-02-20T17:23:14.497259] LOG: [API] GET /get_repeaters.php +[2026-02-20T17:23:14.497296] LOG: [API] Request: none +[2026-02-20T17:23:14.497301] LOG: [API] Response (200) in 0.47s: 667 repeaters +[2026-02-20T17:23:14.497322] LOG: [MAP] Loaded 667 repeaters for zone SEA +[2026-02-20T17:23:14.497330] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA +[2026-02-20T17:23:25.652350] LOG: [APP] App resumed from background +[2026-02-20T17:23:26.427805] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:23:26.430129] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:23:28.176017] LOG: [BLE] Cached device info: MeshCore-Cozmo (F3:16:AF:D8:2B:1E) +[2026-02-20T17:23:28.176612] LOG: [APP] Creating new MeshCoreConnection +[2026-02-20T17:23:28.176880] LOG: [CONN] Step: ConnectionStep.bleConnecting +[2026-02-20T17:23:28.176891] LOG: [BLE] Connection attempt 1/3 to F3:16:AF:D8:2B:1E +[2026-02-20T17:23:28.176915] LOG: [BLE] Device reference created +[2026-02-20T17:23:28.176918] LOG: [BLE] Connecting to GATT... +[2026-02-20T17:23:28.435386] LOG: [BLE] GATT connected +[2026-02-20T17:23:28.847069] LOG: [BLE] MTU negotiated: 247 bytes +[2026-02-20T17:23:28.947639] LOG: [BLE] Discovering services... +[2026-02-20T17:23:29.265835] LOG: [BLE] Found 3 services +[2026-02-20T17:23:29.266082] LOG: [BLE] Found MeshCore service +[2026-02-20T17:23:29.266144] LOG: [BLE] Found TX characteristic +[2026-02-20T17:23:29.266198] LOG: [BLE] Found RX characteristic +[2026-02-20T17:23:29.266212] LOG: [BLE] Enabling notifications... +[2026-02-20T17:23:29.356416] LOG: [BLE] Notifications enabled +[2026-02-20T17:23:29.356535] LOG: [BLE] Device name: MeshCore-Cozmo (from scan: true, platformName: ) +[2026-02-20T17:23:29.356555] LOG: [BLE] Connection complete +[2026-02-20T17:23:29.356579] LOG: [CONN] Step: ConnectionStep.protocolHandshake +[2026-02-20T17:23:29.857651] LOG: [CONN] Step: ConnectionStep.deviceQuery +[2026-02-20T17:23:29.924351] LOG: [CONN] Frame received (80 bytes): 0d 08 af 28 00 00 00 00 32 39 2d 4a 61 6e 2d 32 30 32 36 00 48 65 6c 74 65 63 20 54 31 31 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 31 2e 31 32 2e 30 2d 65 37 33 38 61 37 34 00 00 00 00 00 +[2026-02-20T17:23:29.924426] LOG: [CONN] Response code: 0x0d (13) +[2026-02-20T17:23:29.924431] LOG: [CONN] Firmware version: 8 +[2026-02-20T17:23:29.924440] LOG: [CONN] Build date: 29-Jan-2026 +[2026-02-20T17:23:29.924445] LOG: [CONN] Manufacturer model: Heltec T114v1.12.0-e738a74 +[2026-02-20T17:23:29.986292] LOG: [CONN] Frame received (63 bytes): 05 01 16 16 f9 92 6e f7 f7 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f a5 eb ab b8 d2 02 0f 1a b9 f8 00 00 00 01 bd e4 0d 00 24 f4 00 00 07 05 43 6f 7a 6d 6f +[2026-02-20T17:23:29.986368] LOG: [CONN] Response code: 0x05 (5) +[2026-02-20T17:23:29.986388] LOG: [CONN] SelfInfo received: name="Cozmo", publicKey=F9926EF7F78C5689... +[2026-02-20T17:23:29.986441] LOG: [CONN] Public key acquired: F9926EF7F78C5689... +[2026-02-20T17:23:29.986453] LOG: [CONN] Step: ConnectionStep.powerConfiguration +[2026-02-20T17:23:29.986480] LOG: [CONN] Device identified: Heltec T114 (reports 0.3W / 22dBm) +[2026-02-20T17:23:29.986488] LOG: [CONN] Step: ConnectionStep.timeSync +[2026-02-20T17:23:30.043607] LOG: [CONN] Step: ConnectionStep.slotAcquisition +[2026-02-20T17:23:30.043653] LOG: [CONN] Requesting API session via geo-auth +[2026-02-20T17:23:30.043768] LOG: [APP] Stage 1: Attempting auth with public_key: F9926EF7F78C5689... +[2026-02-20T17:23:30.045077] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:23:30.045101] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:23:30.045105] LOG: [CONN] Received OK response +[2026-02-20T17:23:30.720589] LOG: [API] POST /wardrive-api.php/auth +[2026-02-20T17:23:30.720663] LOG: [API] Request: {"reason":"connect","who":"Cozmo","ver":"APP-1771555184","power":"0.3w","iata":"SEA","model":"Heltec T114","coords":{"lat":47.3378661,"lng":-122.2247461,"accuracy_m":11.083000183105469,"timestamp":1771637010}} +[2026-02-20T17:23:30.720688] LOG: [API] Response (200) in 0.68s: {"success":true,"tx_allowed":true,"rx_allowed":true,"zone":{"name":"Seattle, US","code":"SEA"},"expires_at":1771637310,"type":"API","debug_mode":0,"enforce_hybrid":false,"min_mode_interval":15,"channels":["public","bot","bot-tacoma","olybot","bot-islands","sipesbot"]} +[2026-02-20T17:23:30.721614] LOG: [API] Regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] +[2026-02-20T17:23:30.721653] LOG: [APP] Stage 1 succeeded: authenticated via public_key +[2026-02-20T17:23:30.721668] LOG: [APP] Auth type: API +[2026-02-20T17:23:30.721914] LOG: [CONN] API session acquired successfully (session_id: SEA-20260220-0034) +[2026-02-20T17:23:30.721934] LOG: [CONN] Step: ConnectionStep.channelSetup +[2026-02-20T17:23:30.721947] LOG: [CONN] Creating #wardriving channel +[2026-02-20T17:23:30.721964] LOG: [CHANNEL] Looking up channel: #wardriving +[2026-02-20T17:23:30.721974] LOG: [CONN] getChannel(0) - sending request +[2026-02-20T17:23:30.722006] LOG: [CONN] getChannel bytes: 0x1f 0x00 +[2026-02-20T17:23:30.768441] LOG: [CONN] Frame received (50 bytes): 12 00 50 75 62 6c 69 63 00 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 8b 33 87 e9 c5 cd ea 6a c9 e5 ed ba a1 15 cd 72 +[2026-02-20T17:23:30.768493] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:30.768551] LOG: [CONN] getChannel(1) - sending request +[2026-02-20T17:23:30.768563] LOG: [CONN] getChannel bytes: 0x1f 0x01 +[2026-02-20T17:23:30.827764] LOG: [CONN] Frame received (50 bytes): 12 01 23 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 62 e8 c7 49 22 e1 e3 9e 52 e2 2d 14 7c 9a c0 2f +[2026-02-20T17:23:30.827891] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:30.827929] LOG: [CONN] getChannel(2) - sending request +[2026-02-20T17:23:30.827948] LOG: [CONN] getChannel bytes: 0x1f 0x02 +[2026-02-20T17:23:30.886803] LOG: [CONN] Frame received (50 bytes): 12 02 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:30.886917] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:30.886952] LOG: [CHANNEL] Found empty slot at index 2 +[2026-02-20T17:23:30.886964] LOG: [CONN] getChannel(3) - sending request +[2026-02-20T17:23:30.886985] LOG: [CONN] getChannel bytes: 0x1f 0x03 +[2026-02-20T17:23:30.943951] LOG: [CONN] Frame received (50 bytes): 12 03 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:30.943995] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:30.944005] LOG: [CONN] getChannel(4) - sending request +[2026-02-20T17:23:30.944011] LOG: [CONN] getChannel bytes: 0x1f 0x04 +[2026-02-20T17:23:31.005283] LOG: [CONN] Frame received (50 bytes): 12 04 23 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 83 c8 b0 19 97 65 42 65 93 8d a8 76 5c bc 7d b9 +[2026-02-20T17:23:31.005393] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.005430] LOG: [CONN] getChannel(5) - sending request +[2026-02-20T17:23:31.005449] LOG: [CONN] getChannel bytes: 0x1f 0x05 +[2026-02-20T17:23:31.071519] LOG: [CONN] Frame received (50 bytes): 12 05 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.071653] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.071688] LOG: [CONN] getChannel(6) - sending request +[2026-02-20T17:23:31.071710] LOG: [CONN] getChannel bytes: 0x1f 0x06 +[2026-02-20T17:23:31.127745] LOG: [CONN] Frame received (50 bytes): 12 06 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.127881] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.127909] LOG: [CONN] getChannel(7) - sending request +[2026-02-20T17:23:31.127934] LOG: [CONN] getChannel bytes: 0x1f 0x07 +[2026-02-20T17:23:31.185489] LOG: [CONN] Frame received (50 bytes): 12 07 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.185590] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.185611] LOG: [CONN] getChannel(8) - sending request +[2026-02-20T17:23:31.185631] LOG: [CONN] getChannel bytes: 0x1f 0x08 +[2026-02-20T17:23:31.246401] LOG: [CONN] Frame received (50 bytes): 12 08 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.246666] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.247304] LOG: [CONN] getChannel(9) - sending request +[2026-02-20T17:23:31.247327] LOG: [CONN] getChannel bytes: 0x1f 0x09 +[2026-02-20T17:23:31.306890] LOG: [CONN] Frame received (50 bytes): 12 09 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.306943] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.306982] LOG: [CONN] getChannel(10) - sending request +[2026-02-20T17:23:31.307002] LOG: [CONN] getChannel bytes: 0x1f 0x0a +[2026-02-20T17:23:31.368449] LOG: [CONN] Frame received (50 bytes): 12 0a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.368568] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.368596] LOG: [CONN] getChannel(11) - sending request +[2026-02-20T17:23:31.368622] LOG: [CONN] getChannel bytes: 0x1f 0x0b +[2026-02-20T17:23:31.427308] LOG: [CONN] Frame received (50 bytes): 12 0b 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.427430] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.427465] LOG: [CONN] getChannel(12) - sending request +[2026-02-20T17:23:31.427485] LOG: [CONN] getChannel bytes: 0x1f 0x0c +[2026-02-20T17:23:31.484590] LOG: [CONN] Frame received (50 bytes): 12 0c 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.484648] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.484662] LOG: [CONN] getChannel(13) - sending request +[2026-02-20T17:23:31.484674] LOG: [CONN] getChannel bytes: 0x1f 0x0d +[2026-02-20T17:23:31.546211] LOG: [CONN] Frame received (50 bytes): 12 0d 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.546348] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.546412] LOG: [CONN] getChannel(14) - sending request +[2026-02-20T17:23:31.546432] LOG: [CONN] getChannel bytes: 0x1f 0x0e +[2026-02-20T17:23:31.606501] LOG: [CONN] Frame received (50 bytes): 12 0e 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.606720] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.606755] LOG: [CONN] getChannel(15) - sending request +[2026-02-20T17:23:31.606774] LOG: [CONN] getChannel bytes: 0x1f 0x0f +[2026-02-20T17:23:31.680142] LOG: [CONN] Frame received (50 bytes): 12 0f 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.680185] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.680193] LOG: [CONN] getChannel(16) - sending request +[2026-02-20T17:23:31.680200] LOG: [CONN] getChannel bytes: 0x1f 0x10 +[2026-02-20T17:23:31.725795] LOG: [CONN] Frame received (50 bytes): 12 10 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.725933] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.725968] LOG: [CONN] getChannel(17) - sending request +[2026-02-20T17:23:31.725989] LOG: [CONN] getChannel bytes: 0x1f 0x11 +[2026-02-20T17:23:31.786363] LOG: [CONN] Frame received (50 bytes): 12 11 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.786485] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.786556] LOG: [CONN] getChannel(18) - sending request +[2026-02-20T17:23:31.786579] LOG: [CONN] getChannel bytes: 0x1f 0x12 +[2026-02-20T17:23:31.845947] LOG: [CONN] Frame received (50 bytes): 12 12 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.846066] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.846099] LOG: [CONN] getChannel(19) - sending request +[2026-02-20T17:23:31.846126] LOG: [CONN] getChannel bytes: 0x1f 0x13 +[2026-02-20T17:23:31.906700] LOG: [CONN] Frame received (50 bytes): 12 13 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.906831] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.906866] LOG: [CONN] getChannel(20) - sending request +[2026-02-20T17:23:31.906886] LOG: [CONN] getChannel bytes: 0x1f 0x14 +[2026-02-20T17:23:31.967906] LOG: [CONN] Frame received (50 bytes): 12 14 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:31.968031] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:31.968098] LOG: [CONN] getChannel(21) - sending request +[2026-02-20T17:23:31.968121] LOG: [CONN] getChannel bytes: 0x1f 0x15 +[2026-02-20T17:23:32.028499] LOG: [CONN] Frame received (50 bytes): 12 15 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.028615] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.028644] LOG: [CONN] getChannel(22) - sending request +[2026-02-20T17:23:32.028678] LOG: [CONN] getChannel bytes: 0x1f 0x16 +[2026-02-20T17:23:32.087437] LOG: [CONN] Frame received (50 bytes): 12 16 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.087548] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.087581] LOG: [CONN] getChannel(23) - sending request +[2026-02-20T17:23:32.087601] LOG: [CONN] getChannel bytes: 0x1f 0x17 +[2026-02-20T17:23:32.145852] LOG: [CONN] Frame received (50 bytes): 12 17 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.145967] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.146] LOG: [CONN] getChannel(24) - sending request +[2026-02-20T17:23:32.146020] LOG: [CONN] getChannel bytes: 0x1f 0x18 +[2026-02-20T17:23:32.205869] LOG: [CONN] Frame received (50 bytes): 12 18 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.206025] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.206055] LOG: [CONN] getChannel(25) - sending request +[2026-02-20T17:23:32.206081] LOG: [CONN] getChannel bytes: 0x1f 0x19 +[2026-02-20T17:23:32.268053] LOG: [CONN] Frame received (50 bytes): 12 19 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.268196] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.268234] LOG: [CONN] getChannel(26) - sending request +[2026-02-20T17:23:32.268254] LOG: [CONN] getChannel bytes: 0x1f 0x1a +[2026-02-20T17:23:32.328078] LOG: [CONN] Frame received (50 bytes): 12 1a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.328197] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.328305] LOG: [CONN] getChannel(27) - sending request +[2026-02-20T17:23:32.328330] LOG: [CONN] getChannel bytes: 0x1f 0x1b +[2026-02-20T17:23:32.387626] LOG: [CONN] Frame received (33 bytes): 88 03 ca 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d +[2026-02-20T17:23:32.387745] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:32.416951] LOG: [CONN] Frame received (50 bytes): 12 1b 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.417052] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.417088] LOG: [CONN] getChannel(28) - sending request +[2026-02-20T17:23:32.417110] LOG: [CONN] getChannel bytes: 0x1f 0x1c +[2026-02-20T17:23:32.477648] LOG: [CONN] Frame received (50 bytes): 12 1c 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.477760] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.477793] LOG: [CONN] getChannel(29) - sending request +[2026-02-20T17:23:32.477813] LOG: [CONN] getChannel bytes: 0x1f 0x1d +[2026-02-20T17:23:32.537858] LOG: [CONN] Frame received (50 bytes): 12 1d 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.537990] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.538024] LOG: [CONN] getChannel(30) - sending request +[2026-02-20T17:23:32.538052] LOG: [CONN] getChannel bytes: 0x1f 0x1e +[2026-02-20T17:23:32.627697] LOG: [CONN] Frame received (50 bytes): 12 1e 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.627830] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.627864] LOG: [CONN] getChannel(31) - sending request +[2026-02-20T17:23:32.627884] LOG: [CONN] getChannel bytes: 0x1f 0x1f +[2026-02-20T17:23:32.685223] LOG: [CONN] Frame received (50 bytes): 12 1f 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.685310] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.685337] LOG: [CONN] getChannel(32) - sending request +[2026-02-20T17:23:32.685353] LOG: [CONN] getChannel bytes: 0x1f 0x20 +[2026-02-20T17:23:32.748958] LOG: [CONN] Frame received (50 bytes): 12 20 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.749091] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.749357] LOG: [CONN] getChannel(33) - sending request +[2026-02-20T17:23:32.749410] LOG: [CONN] getChannel bytes: 0x1f 0x21 +[2026-02-20T17:23:32.805291] LOG: [CONN] Frame received (50 bytes): 12 21 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.805380] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.805404] LOG: [CONN] getChannel(34) - sending request +[2026-02-20T17:23:32.805419] LOG: [CONN] getChannel bytes: 0x1f 0x22 +[2026-02-20T17:23:32.865906] LOG: [CONN] Frame received (50 bytes): 12 22 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.865991] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.866012] LOG: [CONN] getChannel(35) - sending request +[2026-02-20T17:23:32.866023] LOG: [CONN] getChannel bytes: 0x1f 0x23 +[2026-02-20T17:23:32.926216] LOG: [CONN] Frame received (50 bytes): 12 23 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.926347] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.926378] LOG: [CONN] getChannel(36) - sending request +[2026-02-20T17:23:32.926412] LOG: [CONN] getChannel bytes: 0x1f 0x24 +[2026-02-20T17:23:32.987593] LOG: [CONN] Frame received (50 bytes): 12 24 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:32.987722] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:32.987760] LOG: [CONN] getChannel(37) - sending request +[2026-02-20T17:23:32.987780] LOG: [CONN] getChannel bytes: 0x1f 0x25 +[2026-02-20T17:23:33.044708] LOG: [CONN] Frame received (50 bytes): 12 25 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:33.044807] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:33.044830] LOG: [CONN] getChannel(38) - sending request +[2026-02-20T17:23:33.044842] LOG: [CONN] getChannel bytes: 0x1f 0x26 +[2026-02-20T17:23:33.107683] LOG: [CONN] Frame received (50 bytes): 12 26 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:33.107804] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:33.107835] LOG: [CONN] getChannel(39) - sending request +[2026-02-20T17:23:33.107860] LOG: [CONN] getChannel bytes: 0x1f 0x27 +[2026-02-20T17:23:33.167946] LOG: [CONN] Frame received (50 bytes): 12 27 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:23:33.168063] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:23:33.168098] LOG: [CONN] getChannel(40) - sending request +[2026-02-20T17:23:33.168119] LOG: [CONN] getChannel bytes: 0x1f 0x28 +[2026-02-20T17:23:33.226057] LOG: [CONN] Frame received (2 bytes): 01 02 +[2026-02-20T17:23:33.226163] LOG: [CONN] Response code: 0x01 (1) +[2026-02-20T17:23:33.226183] LOG: [CONN] Received ERR response (error code: 2) +[2026-02-20T17:23:33.226258] LOG: [CHANNEL] Scan stopped at channel 40 (error: Exception: Command error (code 2)) +[2026-02-20T17:23:33.226276] LOG: [CHANNEL] #wardriving not found in 40 channels, creating at index 2 +[2026-02-20T17:23:33.226291] LOG: [CRYPTO] Deriving channel key for: #wardriving +[2026-02-20T17:23:33.226453] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.284849] LOG: [CHANNEL] Channel #wardriving created successfully at index 2 +[2026-02-20T17:23:33.284963] LOG: [CONN] Channel ready: #wardriving (CH:2) +[2026-02-20T17:23:33.284982] LOG: [CONN] Step: ConnectionStep.gpsInit +[2026-02-20T17:23:33.284998] LOG: [CONN] Step: ConnectionStep.connected +[2026-02-20T17:23:33.285012] LOG: [CONN] Connection workflow complete +[2026-02-20T17:23:33.285131] LOG: [APP] Device public key stored: F9926EF7F78C5689... +[2026-02-20T17:23:33.285148] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:33.285183] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:33.287019] LOG: [APP] Saved last connected device: Cozmo +[2026-02-20T17:23:33.485964] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:23:33.486176] LOG: [CONN] Started battery polling (30s interval) +[2026-02-20T17:23:33.486194] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:33.486229] LOG: [CONN] Started noise floor polling (5s interval) +[2026-02-20T17:23:33.486343] LOG: [MODEL] Device recognized: Heltec T114 - reporting 0.3W in API calls +[2026-02-20T17:23:33.486357] LOG: [APP] Creating unified RX handler +[2026-02-20T17:23:33.486500] LOG: [APP] TxTracker.carpeaterPrefix set to CC +[2026-02-20T17:23:33.486598] LOG: [APP] TxTracker.onCarpeaterDrop callback SET +[2026-02-20T17:23:33.486706] LOG: [APP] PacketValidator configured with 1 channels: Public +[2026-02-20T17:23:33.486725] LOG: [UNIFIED RX] Starting unified RX listening +[2026-02-20T17:23:33.486734] LOG: [UNIFIED RX] ✅ Unified listening started successfully +[2026-02-20T17:23:33.486746] LOG: [APP] Unified RX handler created and listening +[2026-02-20T17:23:33.486894] LOG: [CHANNEL] Setting regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] +[2026-02-20T17:23:33.486920] LOG: [CRYPTO] Deriving channel key for: #wardriving +[2026-02-20T17:23:33.486976] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487] LOG: [CHANNEL] Added: #wardriving -> hash=129 +[2026-02-20T17:23:33.487013] LOG: [CRYPTO] Deriving channel key for: #bot +[2026-02-20T17:23:33.487038] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487063] LOG: [CHANNEL] Added: #bot -> hash=202 +[2026-02-20T17:23:33.487074] LOG: [CRYPTO] Deriving channel key for: #bot-tacoma +[2026-02-20T17:23:33.487110] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487128] LOG: [CHANNEL] Added: #bot-tacoma -> hash=5 +[2026-02-20T17:23:33.487143] LOG: [CRYPTO] Deriving channel key for: #olybot +[2026-02-20T17:23:33.487162] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487185] LOG: [CHANNEL] Added: #olybot -> hash=221 +[2026-02-20T17:23:33.487195] LOG: [CRYPTO] Deriving channel key for: #bot-islands +[2026-02-20T17:23:33.487239] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487261] LOG: [CHANNEL] Added: #bot-islands -> hash=183 +[2026-02-20T17:23:33.487271] LOG: [CRYPTO] Deriving channel key for: #sipesbot +[2026-02-20T17:23:33.487295] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:23:33.487315] LOG: [CHANNEL] Added: #sipesbot -> hash=97 +[2026-02-20T17:23:33.487326] LOG: [CHANNEL] Total channels: 7 +[2026-02-20T17:23:33.487361] LOG: [APP] Regional channels configured: [#bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot] +[2026-02-20T17:23:33.487390] LOG: [UNIFIED RX] Validator updated with new channel configuration +[2026-02-20T17:23:33.487408] LOG: [APP] PacketValidator updated with 7 channels: Public, #wardriving, #bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot +[2026-02-20T17:23:33.487428] LOG: [CONN] No regional scope — using unscoped flood +[2026-02-20T17:23:33.487446] LOG: [HIVE] Opening box "remembered_device"... +[2026-02-20T17:23:33.487799] LOG: [HIVE] Box "remembered_device" opened successfully +[2026-02-20T17:23:33.489907] LOG: [APP] Saved remembered device: MeshCore-Cozmo +[2026-02-20T17:23:33.490084] LOG: [APP] Display name set: "Cozmo" +[2026-02-20T17:23:33.490118] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:23:33.490162] LOG: [APP] Restored antenna preference for "Cozmo": external +[2026-02-20T17:23:33.490175] LOG: [CONN] Connected with full access (TX + RX allowed) +[2026-02-20T17:23:33.490201] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:23:33.490902] LOG: [APP] Saved preferences +[2026-02-20T17:23:34.339478] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:23:34.339633] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:23:34.339646] LOG: [CONN] Received OK response +[2026-02-20T17:23:34.365774] LOG: [CONN] Frame received (11 bytes): 0c f7 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:23:34.365889] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:23:34.365908] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:23:34.365931] LOG: [CONN] Battery updated: 4087mV (91%) +[2026-02-20T17:23:34.366472] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ca 03 04 00 00 00 cd 22 00 00 +[2026-02-20T17:23:34.366500] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:34.366586] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:23:37.803214] LOG: [CONN] Frame received (143 bytes): 88 2f b8 15 07 51 01 7a 1e e0 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 07 a0 bd +[2026-02-20T17:23:37.803251] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:37.803292] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:37.803348] LOG: [RX PARSE] RAW Packet (140 bytes): 15 07 51 01 7A 1E E0 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 07 A0 BD +[2026-02-20T17:23:37.803363] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:37.803369] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T17:23:37.803387] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x51, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=131 bytes +[2026-02-20T17:23:37.803396] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T17:23:38.314167] LOG: [CONN] Frame received (143 bytes): 88 31 b9 15 07 51 01 7a 1e e0 7e cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 07 a0 bd +[2026-02-20T17:23:38.314334] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:38.314367] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:38.314500] LOG: [RX PARSE] RAW Packet (140 bytes): 15 07 51 01 7A 1E E0 7E CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 07 A0 BD +[2026-02-20T17:23:38.314597] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:38.314610] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T17:23:38.314641] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x51, lastHop=0xcc, SNR=12.25, RSSI=-71, payload=131 bytes +[2026-02-20T17:23:38.314660] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T17:23:38.486833] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:38.656163] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b9 31 04 00 00 00 ce 22 00 00 +[2026-02-20T17:23:38.656313] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:38.656335] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:23:41.427685] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:23:41.427767] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:23:43.486866] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:43.695488] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b9 31 04 00 00 00 ce 22 00 00 +[2026-02-20T17:23:43.695608] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:43.695624] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:23:48.486920] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:48.586967] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 31 04 00 00 00 ce 22 00 00 +[2026-02-20T17:23:48.587109] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:48.587130] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:23:50.672853] LOG: [CONN] Frame received (146 bytes): 88 31 b8 15 0d 51 01 7a 1e e0 7e c5 75 20 20 53 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 +[2026-02-20T17:23:50.672950] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:50.672973] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:50.673029] LOG: [RX PARSE] RAW Packet (143 bytes): 15 0D 51 01 7A 1E E0 7E C5 75 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 +[2026-02-20T17:23:50.673041] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:50.673050] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T17:23:50.673063] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x51, lastHop=0xdd, SNR=12.25, RSSI=-72, payload=128 bytes +[2026-02-20T17:23:50.673072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T17:23:51.773094] LOG: [SESSION] Checking session validity via heartbeat... +[2026-02-20T17:23:51.933636] LOG: [CONN] Frame received (147 bytes): 88 2f b9 15 0e 51 01 7a 1e e0 7e c5 75 20 20 53 7e dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 +[2026-02-20T17:23:51.933753] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:51.933780] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:51.933876] LOG: [RX PARSE] RAW Packet (144 bytes): 15 0E 51 01 7A 1E E0 7E C5 75 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 +[2026-02-20T17:23:51.933897] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:51.933907] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T17:23:51.933930] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x51, lastHop=0xcc, SNR=11.75, RSSI=-71, payload=128 bytes +[2026-02-20T17:23:51.933941] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T17:23:52.114568] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T17:23:52.114682] LOG: [API] Request: {"heartbeat":true,"has_coords":true} +[2026-02-20T17:23:52.114697] LOG: [API] Response (200) in 0.34s: {"success":true,"expires_at":1771637332} +[2026-02-20T17:23:52.114736] LOG: [SESSION] Session is valid (expires_at: 1771637332) +[2026-02-20T17:23:52.114802] LOG: [PING] Starting auto mode: active +[2026-02-20T17:23:52.114815] LOG: [PING] Auto-ping interval set to 30000ms +[2026-02-20T17:23:52.114832] LOG: [PING] Using interval from preferences: 30s (30000ms) +[2026-02-20T17:23:52.114846] LOG: [AUTO] enableAutoPing called (passiveMode=false, hybridMode=false) +[2026-02-20T17:23:52.114857] LOG: [AUTO] Acquiring wake lock for auto mode +[2026-02-20T17:23:52.116338] LOG: [WAKELOCK] Screen wake lock enabled +[2026-02-20T17:23:52.116354] LOG: [ACTIVE MODE] Sending initial auto ping +[2026-02-20T17:23:52.116365] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T17:23:52.116394] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T17:23:52.116442] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.33787, -122.22475 [0.3w]" +[2026-02-20T17:23:52.116460] LOG: [TX LOG] Starting echo tracking +[2026-02-20T17:23:52.116470] LOG: [TX LOG] Payload: "@[MapperBot] 47.33787, -122.22475 [0.3w]" +[2026-02-20T17:23:52.116483] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T17:23:52.116502] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T17:23:52.116514] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T17:23:52.116524] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T17:23:52.116547] LOG: [CONN] Sending ping: @[MapperBot] 47.33787, -122.22475 [0.3w] +[2026-02-20T17:23:52.116615] LOG: [RX LOG] Starting passive RX wardriving +[2026-02-20T17:23:52.116874] LOG: [GRAPH] Started active noise floor session +[2026-02-20T17:23:52.116889] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T17:23:52.116908] LOG: [HEARTBEAT] Heartbeat mode enabled +[2026-02-20T17:23:52.116919] LOG: [HEARTBEAT] Enabled for active Mode +[2026-02-20T17:23:52.116929] LOG: [BACKGROUND] Starting background service (mode: Active Mode) +[2026-02-20T17:23:52.136471] LOG: [BACKGROUND] Background service started +[2026-02-20T17:23:52.278962] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:23:52.279072] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:23:52.279083] LOG: [CONN] Received OK response +[2026-02-20T17:23:53.487070] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:53.537486] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 2f 04 00 00 00 cf 22 00 00 +[2026-02-20T17:23:53.537606] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:53.537630] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:23:53.810729] LOG: [CONN] Frame received (73 bytes): 88 33 ba 15 01 cc 81 cf 4f 3c 5b a7 8b 88 d0 50 1f a7 55 76 a1 d2 d1 86 94 ca 29 8b 67 ce 86 ed 39 61 d7 87 88 d5 7a 58 80 4b 4b 25 30 80 59 13 5a a4 af 71 a7 f0 45 48 e2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T17:23:53.810854] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:53.810890] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:53.810962] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 CF 4F 3C 5B A7 8B 88 D0 50 1F A7 55 76 A1 D2 D1 86 94 CA 29 8B 67 CE 86 ED 39 61 D7 87 88 D5 7A 58 80 4B 4B 25 30 80 59 13 5A A4 AF 71 A7 F0 45 48 E2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T17:23:53.810978] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:53.810994] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T17:23:53.811021] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-70, payload=67 bytes +[2026-02-20T17:23:53.811040] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T17:23:53.811052] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T17:23:53.811064] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-70 +[2026-02-20T17:23:53.811087] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T17:23:53.811098] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T17:23:53.811111] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T17:23:53.811126] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T17:23:53.811136] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T17:23:55.284149] LOG: [PING] Ping sent successfully +[2026-02-20T17:23:56.427862] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:23:56.427960] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:23:57.117169] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T17:23:58.486674] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:23:58.546421] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 33 04 00 00 00 cf 22 00 00 +[2026-02-20T17:23:58.546600] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:23:58.546620] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:23:59.344641] LOG: [CONN] Frame received (146 bytes): 88 2f b8 15 11 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 53 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 +[2026-02-20T17:23:59.344761] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:23:59.344787] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:23:59.344883] LOG: [RX PARSE] RAW Packet (143 bytes): 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:23:59.344903] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:23:59.344911] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T17:23:59.344932] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0x51, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=124 bytes +[2026-02-20T17:23:59.344943] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T17:23:59.344955] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T17:23:59.344964] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T17:23:59.345050] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T17:23:59.345063] LOG: [RX FILTER] Raw packet (143 bytes): 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:23:59.345084] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 11.75 +[2026-02-20T17:23:59.345097] LOG: [RX FILTER] ✓ RSSI OK (-72 < -30) +[2026-02-20T17:23:59.345105] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T17:23:59.345118] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T17:23:59.345127] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T17:23:59.345136] LOG: [RX FILTER] Encrypted message: 121 bytes +[2026-02-20T17:23:59.345149] LOG: [CRYPTO] Decrypting message (121 bytes) +[2026-02-20T17:23:59.345393] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T17:23:59.345449] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T17:23:59.345614] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T17:23:59.345755] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T17:23:59.345764] LOG: [RX LOG] Dropped packet hex: 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:24:00.284691] LOG: [PING] RX listening window ended +[2026-02-20T17:24:00.284803] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T17:24:00.284829] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T17:24:00.284923] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T17:24:00.284933] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T17:24:00.284942] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T17:24:00.284964] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T17:24:00.284975] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T17:24:00.285320] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T17:24:01.743334] LOG: [CONN] Frame received (147 bytes): 88 30 ba 15 12 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 53 7e dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 +[2026-02-20T17:24:01.743367] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:01.743391] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:01.743447] LOG: [RX PARSE] RAW Packet (144 bytes): 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:24:01.743460] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:24:01.743467] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T17:24:01.743482] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x51, lastHop=0xcc, SNR=12.0, RSSI=-70, payload=124 bytes +[2026-02-20T17:24:01.743490] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T17:24:01.743494] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T17:24:01.743500] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T17:24:01.743552] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T17:24:01.743559] LOG: [RX FILTER] Raw packet (144 bytes): 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:24:01.743572] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.0 +[2026-02-20T17:24:01.743578] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) +[2026-02-20T17:24:01.743583] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T17:24:01.743590] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T17:24:01.743595] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T17:24:01.743600] LOG: [RX FILTER] Encrypted message: 121 bytes +[2026-02-20T17:24:01.743606] LOG: [CRYPTO] Decrypting message (121 bytes) +[2026-02-20T17:24:01.743717] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T17:24:01.743792] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T17:24:01.743898] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T17:24:01.743969] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T17:24:01.743974] LOG: [RX LOG] Dropped packet hex: 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 +[2026-02-20T17:24:01.934116] LOG: [PING] Stopping auto mode: active +[2026-02-20T17:24:01.934242] LOG: [PING] disableAutoPing called +[2026-02-20T17:24:01.935601] LOG: [WAKELOCK] Screen wake lock disabled +[2026-02-20T17:24:01.935646] LOG: [PING] Auto-ping disabled +[2026-02-20T17:24:01.935662] LOG: [PING] Stopping TX echo tracking and RX window timer +[2026-02-20T17:24:01.935674] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T17:24:01.935683] LOG: [RX LOG] Stopping passive RX wardriving: trigger=user_stop +[2026-02-20T17:24:01.935698] LOG: [RX BATCH] Flushing all repeaters, trigger=user_stop, active_repeaters=0 +[2026-02-20T17:24:01.935707] LOG: [RX BATCH] No repeaters to flush +[2026-02-20T17:24:01.935718] LOG: [BACKGROUND] Stopping background service +[2026-02-20T17:24:01.935776] LOG: [BACKGROUND] Background service stopped +[2026-02-20T17:24:01.935848] LOG: [GRAPH] Ended session: 0:09, 2 samples, 1 markers +[2026-02-20T17:24:01.942189] LOG: [HEARTBEAT] Heartbeat mode disabled +[2026-02-20T17:24:01.942251] LOG: [ACTIVE MODE] Shared cooldown started (5s) - blocks TX Ping and TX modes +[2026-02-20T17:24:03.486952] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:24:03.487085] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:03.585481] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:24:03.585584] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:24:03.585604] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:24:03.585617] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T17:24:03.645696] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 30 04 00 00 00 d0 22 00 00 +[2026-02-20T17:24:03.645780] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:03.645793] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:24:05.286047] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T17:24:05.286370] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T17:24:05.286386] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T17:24:05.756095] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T17:24:05.756177] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T17:24:05.756200] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771637345} +[2026-02-20T17:24:05.756222] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T17:24:05.756769] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T17:24:05.756787] LOG: [APP] Upload success: +1 items (total: 1) +[2026-02-20T17:24:06.943286] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T17:24:08.487036] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:08.656245] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 30 04 00 00 00 d0 22 00 00 +[2026-02-20T17:24:08.656364] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:08.656392] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:24:08.720164] LOG: [CONN] Frame received (148 bytes): 88 2e b8 15 16 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 20 20 20 75 a5 e8 9b dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 +[2026-02-20T17:24:08.720235] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:08.720258] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:08.720307] LOG: [RX PARSE] RAW Packet (145 bytes): 15 16 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 20 20 20 75 A5 E8 9B DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 +[2026-02-20T17:24:08.720317] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:24:08.720327] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T17:24:08.720345] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x51, lastHop=0xdd, SNR=11.5, RSSI=-72, payload=121 bytes +[2026-02-20T17:24:08.720353] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T17:24:10.329734] LOG: [CONN] Frame received (149 bytes): 88 2f ba 15 17 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 20 20 20 75 a5 e8 9b dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 +[2026-02-20T17:24:10.329819] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:10.329838] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:10.329892] LOG: [RX PARSE] RAW Packet (146 bytes): 15 17 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 20 20 20 75 A5 E8 9B DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 +[2026-02-20T17:24:10.329904] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:24:10.329913] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T17:24:10.329924] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0x51, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=121 bytes +[2026-02-20T17:24:10.329933] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 +[2026-02-20T17:24:10.758035] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T17:24:11.428058] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:24:11.428171] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:24:13.486626] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:13.668239] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff ba 2f 04 00 00 00 d1 22 00 00 +[2026-02-20T17:24:13.668396] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:13.668423] LOG: [CONN] Noise floor updated: -117dBm +[2026-02-20T17:24:18.487340] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:18.676312] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2f 04 00 00 00 d1 22 00 00 +[2026-02-20T17:24:18.676418] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:18.676433] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:24:19.353041] LOG: [CONN] Frame received (33 bytes): 88 32 b8 21 0a 73 86 7e 75 20 20 20 53 7e dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 1c +[2026-02-20T17:24:19.353173] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:19.353212] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:19.353257] LOG: [RX PARSE] RAW Packet (30 bytes): 21 0A 73 86 7E 75 20 20 20 53 7E DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 1C +[2026-02-20T17:24:19.353271] LOG: [RX PARSE] Header: 0x21, Route type: 1 +[2026-02-20T17:24:19.353286] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T17:24:19.353317] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=10, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-72, payload=18 bytes +[2026-02-20T17:24:19.353335] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=10 +[2026-02-20T17:24:20.132913] LOG: [CONN] Frame received (34 bytes): 88 31 bb 21 0b 73 86 7e 75 20 20 20 53 7e dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 1c +[2026-02-20T17:24:20.133052] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:20.133090] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:20.133135] LOG: [RX PARSE] RAW Packet (31 bytes): 21 0B 73 86 7E 75 20 20 20 53 7E DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 1C +[2026-02-20T17:24:20.133148] LOG: [RX PARSE] Header: 0x21, Route type: 1 +[2026-02-20T17:24:20.133163] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T17:24:20.133185] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=11, firstHop=0x73, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=18 bytes +[2026-02-20T17:24:20.133198] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=11 +[2026-02-20T17:24:22.354205] LOG: [CONN] Frame received (40 bytes): 88 2f ba 21 12 73 86 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 7e dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 +[2026-02-20T17:24:22.354266] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:22.354310] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:22.354354] LOG: [RX PARSE] RAW Packet (37 bytes): 21 12 73 86 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 7E DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 +[2026-02-20T17:24:22.354373] LOG: [RX PARSE] Header: 0x21, Route type: 1 +[2026-02-20T17:24:22.354385] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T17:24:22.354413] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=18, firstHop=0x73, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=17 bytes +[2026-02-20T17:24:22.354427] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=18 +[2026-02-20T17:24:23.487194] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:23.596603] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2f 04 00 00 00 d1 22 00 00 +[2026-02-20T17:24:23.596720] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:23.596742] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:24:25.560985] LOG: [CONN] Frame received (45 bytes): 88 32 ba 01 17 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 38 7e cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 +[2026-02-20T17:24:25.561042] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:25.561054] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:25.561067] LOG: [RX PARSE] RAW Packet (42 bytes): 01 17 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 38 7E CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 +[2026-02-20T17:24:25.561071] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:25.561074] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T17:24:25.561083] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=23, firstHop=0x73, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=17 bytes +[2026-02-20T17:24:25.561086] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=23 +[2026-02-20T17:24:25.830973] LOG: [CONN] Frame received (48 bytes): 88 2f b9 01 1a 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 1e 8e 1f 9b dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 +[2026-02-20T17:24:25.831124] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:25.831157] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:25.831208] LOG: [RX PARSE] RAW Packet (45 bytes): 01 1A 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 1E 8E 1F 9B DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 +[2026-02-20T17:24:25.831228] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:25.831240] LOG: [RX PARSE] Path length offset: 1, Path length: 26 +[2026-02-20T17:24:25.831276] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=26, firstHop=0x73, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=17 bytes +[2026-02-20T17:24:25.831291] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=26 +[2026-02-20T17:24:26.427785] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:24:26.427909] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:24:27.725432] LOG: [CONN] Frame received (51 bytes): 88 34 b9 01 1e 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 +[2026-02-20T17:24:27.725611] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:27.725653] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:27.725706] LOG: [RX PARSE] RAW Packet (48 bytes): 01 1E 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 +[2026-02-20T17:24:27.725722] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:27.725738] LOG: [RX PARSE] Path length offset: 1, Path length: 30 +[2026-02-20T17:24:27.725773] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=30, firstHop=0x73, lastHop=0xcc, SNR=13.0, RSSI=-71, payload=16 bytes +[2026-02-20T17:24:27.725791] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=30 +[2026-02-20T17:24:28.083245] LOG: [CONN] Frame received (53 bytes): 88 2d b7 01 20 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e 9d 9b dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 +[2026-02-20T17:24:28.083373] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:28.083401] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:28.083462] LOG: [RX PARSE] RAW Packet (50 bytes): 01 20 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E 9D 9B DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 +[2026-02-20T17:24:28.083477] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:28.083494] LOG: [RX PARSE] Path length offset: 1, Path length: 32 +[2026-02-20T17:24:28.083523] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=32, firstHop=0x73, lastHop=0xdd, SNR=11.25, RSSI=-73, payload=16 bytes +[2026-02-20T17:24:28.083543] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=32 +[2026-02-20T17:24:28.486725] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:28.574735] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b7 2d 04 00 00 00 d2 22 00 00 +[2026-02-20T17:24:28.574781] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:28.574787] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:24:29.251527] LOG: [CONN] Frame received (51 bytes): 88 32 b8 01 26 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 75 2b 24 a5 9d dd 1e a8 69 18 73 3a 7e dd +[2026-02-20T17:24:29.251620] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:29.251634] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:29.251649] LOG: [RX PARSE] RAW Packet (48 bytes): 01 26 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 75 2B 24 A5 9D DD 1E A8 69 18 73 3A 7E DD +[2026-02-20T17:24:29.251655] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:29.251658] LOG: [RX PARSE] Path length offset: 1, Path length: 38 +[2026-02-20T17:24:29.251670] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=38, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-72, payload=8 bytes +[2026-02-20T17:24:29.251674] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=38 +[2026-02-20T17:24:29.761691] LOG: [CONN] Frame received (52 bytes): 88 33 ba 01 27 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 75 2b 24 a5 9d dd cc 1e a8 69 18 73 3a 7e dd +[2026-02-20T17:24:29.761763] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:29.761786] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:29.761812] LOG: [RX PARSE] RAW Packet (49 bytes): 01 27 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 75 2B 24 A5 9D DD CC 1E A8 69 18 73 3A 7E DD +[2026-02-20T17:24:29.761821] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:29.761826] LOG: [RX PARSE] Path length offset: 1, Path length: 39 +[2026-02-20T17:24:29.761837] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=39, firstHop=0x73, lastHop=0xcc, SNR=12.75, RSSI=-70, payload=8 bytes +[2026-02-20T17:24:29.761846] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=39 +[2026-02-20T17:24:33.091381] LOG: [CONN] Frame received (55 bytes): 88 2f b8 01 2d 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 f4 f1 ea 65 7d e8 9b dd 1e a8 69 18 73 +[2026-02-20T17:24:33.091405] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:33.091421] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:33.091439] LOG: [RX PARSE] RAW Packet (52 bytes): 01 2D 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 F4 F1 EA 65 7D E8 9B DD 1E A8 69 18 73 +[2026-02-20T17:24:33.091443] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:33.091448] LOG: [RX PARSE] Path length offset: 1, Path length: 45 +[2026-02-20T17:24:33.091463] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=45, firstHop=0x73, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=5 bytes +[2026-02-20T17:24:33.091467] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=45 +[2026-02-20T17:24:33.359062] LOG: [CONN] Frame received (56 bytes): 88 30 b9 01 2e 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 f4 f1 ea 65 7d e8 9b dd cc 1e a8 69 18 73 +[2026-02-20T17:24:33.359156] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:33.359179] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:33.359231] LOG: [RX PARSE] RAW Packet (53 bytes): 01 2E 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 F4 F1 EA 65 7D E8 9B DD CC 1E A8 69 18 73 +[2026-02-20T17:24:33.359235] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:33.359243] LOG: [RX PARSE] Path length offset: 1, Path length: 46 +[2026-02-20T17:24:33.359255] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=46, firstHop=0x73, lastHop=0xcc, SNR=12.0, RSSI=-71, payload=5 bytes +[2026-02-20T17:24:33.359262] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=46 +[2026-02-20T17:24:33.486728] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:24:33.486841] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:33.554131] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:24:33.554159] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:24:33.554163] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:24:33.554166] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T17:24:33.614189] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff b9 30 04 00 00 00 d3 22 00 00 +[2026-02-20T17:24:33.614223] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:33.614230] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T17:24:38.487055] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:38.657190] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 30 04 00 00 00 d3 22 00 00 +[2026-02-20T17:24:38.657341] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:38.657384] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:24:40.082447] LOG: [CONN] Frame received (69 bytes): 88 32 b6 01 30 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e e0 7a 61 a4 c9 ca ab 99 2a 94 de a4 5d cd 6c 13 e8 32 dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 46 +[2026-02-20T17:24:40.082561] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:40.082606] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:40.082648] LOG: [RX PARSE] RAW Packet (66 bytes): 01 30 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E E0 7A 61 A4 C9 CA AB 99 2A 94 DE A4 5D CD 6C 13 E8 32 DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 46 +[2026-02-20T17:24:40.082658] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:40.082662] LOG: [RX PARSE] Path length offset: 1, Path length: 48 +[2026-02-20T17:24:40.082675] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=48, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-74, payload=16 bytes +[2026-02-20T17:24:40.082682] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=48 +[2026-02-20T17:24:40.562890] LOG: [CONN] Frame received (70 bytes): 88 32 ba 01 31 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e e0 7a 61 a4 c9 ca ab 99 2a 94 de a4 5d cd 6c 13 e8 32 dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 46 +[2026-02-20T17:24:40.563033] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:40.563061] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:40.563115] LOG: [RX PARSE] RAW Packet (67 bytes): 01 31 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E E0 7A 61 A4 C9 CA AB 99 2A 94 DE A4 5D CD 6C 13 E8 32 DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 46 +[2026-02-20T17:24:40.563127] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T17:24:40.563140] LOG: [RX PARSE] Path length offset: 1, Path length: 49 +[2026-02-20T17:24:40.563160] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=49, firstHop=0x73, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=16 bytes +[2026-02-20T17:24:40.563173] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=49 +[2026-02-20T17:24:41.428065] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:24:41.428196] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:24:43.487099] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:43.604832] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 32 04 00 00 00 d4 22 00 00 +[2026-02-20T17:24:43.604911] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:43.604923] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:24:44.343077] LOG: [CONN] Frame received (44 bytes): 88 34 b5 05 03 24 7e dd bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b 7b 13 57 20 68 66 16 a9 33 +[2026-02-20T17:24:44.343196] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:44.343219] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:44.343264] LOG: [RX PARSE] RAW Packet (41 bytes): 05 03 24 7E DD BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B 7B 13 57 20 68 66 16 A9 33 +[2026-02-20T17:24:44.343278] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:44.343286] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T17:24:44.343308] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x24, lastHop=0xdd, SNR=13.0, RSSI=-75, payload=36 bytes +[2026-02-20T17:24:44.343319] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 +[2026-02-20T17:24:44.896398] LOG: [CONN] Frame received (44 bytes): 88 34 b9 05 03 24 7e cc bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b 7b 13 57 20 68 66 16 a9 33 +[2026-02-20T17:24:44.896560] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:44.896602] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:44.896650] LOG: [RX PARSE] RAW Packet (41 bytes): 05 03 24 7E CC BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B 7B 13 57 20 68 66 16 A9 33 +[2026-02-20T17:24:44.896665] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:44.896680] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T17:24:44.896708] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x24, lastHop=0xcc, SNR=13.0, RSSI=-71, payload=36 bytes +[2026-02-20T17:24:44.896722] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 +[2026-02-20T17:24:45.484095] LOG: [CONN] Frame received (76 bytes): 88 32 b6 05 03 86 7e dd bf be b8 0c 2b 14 d5 4c 6c 3f 92 45 98 d1 d2 3e 11 24 b8 33 9b ff e0 87 8d dc 7b ab 69 e0 56 68 3f 8c 40 ce 61 ec 4a d3 d7 bf 6f 13 af 2a d5 10 8f 2c bd 63 2c fb 87 91 ca 71 93 71 6e da 77 b6 7a 4f 48 e2 +[2026-02-20T17:24:45.484275] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:45.484316] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:45.484390] LOG: [RX PARSE] RAW Packet (73 bytes): 05 03 86 7E DD BF BE B8 0C 2B 14 D5 4C 6C 3F 92 45 98 D1 D2 3E 11 24 B8 33 9B FF E0 87 8D DC 7B AB 69 E0 56 68 3F 8C 40 CE 61 EC 4A D3 D7 BF 6F 13 AF 2A D5 10 8F 2C BD 63 2C FB 87 91 CA 71 93 71 6E DA 77 B6 7A 4F 48 E2 +[2026-02-20T17:24:45.484407] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:45.484423] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T17:24:45.484451] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x86, lastHop=0xdd, SNR=12.5, RSSI=-74, payload=68 bytes +[2026-02-20T17:24:45.484466] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 +[2026-02-20T17:24:46.174304] LOG: [CONN] Frame received (76 bytes): 88 2e b8 05 03 86 7e cc bf be b8 0c 2b 14 d5 4c 6c 3f 92 45 98 d1 d2 3e 11 24 b8 33 9b ff e0 87 8d dc 7b ab 69 e0 56 68 3f 8c 40 ce 61 ec 4a d3 d7 bf 6f 13 af 2a d5 10 8f 2c bd 63 2c fb 87 91 ca 71 93 71 6e da 77 b6 7a 4f 48 e2 +[2026-02-20T17:24:46.174476] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:46.174590] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:46.174679] LOG: [RX PARSE] RAW Packet (73 bytes): 05 03 86 7E CC BF BE B8 0C 2B 14 D5 4C 6C 3F 92 45 98 D1 D2 3E 11 24 B8 33 9B FF E0 87 8D DC 7B AB 69 E0 56 68 3F 8C 40 CE 61 EC 4A D3 D7 BF 6F 13 AF 2A D5 10 8F 2C BD 63 2C FB 87 91 CA 71 93 71 6E DA 77 B6 7A 4F 48 E2 +[2026-02-20T17:24:46.174695] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:46.174712] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T17:24:46.174738] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x86, lastHop=0xcc, SNR=11.5, RSSI=-72, payload=68 bytes +[2026-02-20T17:24:46.174757] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 +[2026-02-20T17:24:48.487786] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:48.616450] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 2e 04 00 00 00 d5 22 00 00 +[2026-02-20T17:24:48.616580] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:48.616600] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:24:50.396122] LOG: [CONN] Frame received (49 bytes): 88 31 bb 05 11 24 7e 75 20 20 20 20 20 20 20 20 20 53 c7 32 9b cc bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b +[2026-02-20T17:24:50.396199] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:50.396217] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:50.396239] LOG: [RX PARSE] RAW Packet (46 bytes): 05 11 24 7E 75 20 20 20 20 20 20 20 20 20 53 C7 32 9B CC BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B +[2026-02-20T17:24:50.396244] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:50.396251] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T17:24:50.396268] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=17, firstHop=0x24, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=27 bytes +[2026-02-20T17:24:50.396275] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=17 +[2026-02-20T17:24:50.939451] LOG: [CONN] Frame received (49 bytes): 88 33 b8 05 11 24 7e 75 20 20 20 20 20 20 20 20 20 53 c7 32 2a dd bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b +[2026-02-20T17:24:50.939621] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:24:50.939653] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:24:50.939707] LOG: [RX PARSE] RAW Packet (46 bytes): 05 11 24 7E 75 20 20 20 20 20 20 20 20 20 53 C7 32 2A DD BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B +[2026-02-20T17:24:50.939722] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T17:24:50.939734] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T17:24:50.939770] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=17, firstHop=0x24, lastHop=0xdd, SNR=12.75, RSSI=-72, payload=27 bytes +[2026-02-20T17:24:50.939784] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=17 +[2026-02-20T17:24:53.487354] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:53.536457] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 33 04 00 00 00 d5 22 00 00 +[2026-02-20T17:24:53.536578] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:53.536605] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:24:56.427799] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:24:56.427916] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:24:58.486922] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:24:58.576118] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 33 04 00 00 00 d5 22 00 00 +[2026-02-20T17:24:58.576220] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:24:58.576245] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:01.708369] LOG: [CONN] Frame received (47 bytes): 88 30 b8 15 07 8b 17 9d 32 74 7e dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b 1b 13 c4 +[2026-02-20T17:25:01.708387] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:01.708401] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:01.708410] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 8B 17 9D 32 74 7E DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B 1B 13 C4 +[2026-02-20T17:25:01.708413] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:01.708417] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T17:25:01.708427] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x8b, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=35 bytes +[2026-02-20T17:25:01.708433] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T17:25:02.551164] LOG: [CONN] Frame received (48 bytes): 88 2f bb 15 08 8b 17 9d 32 74 7e dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b 1b 13 c4 +[2026-02-20T17:25:02.551213] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:02.551224] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:02.551234] LOG: [RX PARSE] RAW Packet (45 bytes): 15 08 8B 17 9D 32 74 7E DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B 1B 13 C4 +[2026-02-20T17:25:02.551236] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:02.551240] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T17:25:02.551246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x8b, lastHop=0xcc, SNR=11.75, RSSI=-69, payload=35 bytes +[2026-02-20T17:25:02.551250] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T17:25:03.486820] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:25:03.487007] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:03.644406] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:25:03.644447] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:25:03.644454] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:25:03.644463] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T17:25:03.734645] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bb 2f 04 00 00 00 d5 22 00 00 +[2026-02-20T17:25:03.734687] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:03.734693] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:07.279047] LOG: [CONN] Frame received (58 bytes): 88 31 b9 15 15 8b 17 9d 32 74 7e 75 20 20 20 20 75 e9 24 08 7a cf 9d 32 2a dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b +[2026-02-20T17:25:07.279106] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:07.279149] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:07.279210] LOG: [RX PARSE] RAW Packet (55 bytes): 15 15 8B 17 9D 32 74 7E 75 20 20 20 20 75 E9 24 08 7A CF 9D 32 2A DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B +[2026-02-20T17:25:07.279227] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:07.279245] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T17:25:07.279270] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x8b, lastHop=0xdd, SNR=12.25, RSSI=-71, payload=32 bytes +[2026-02-20T17:25:07.279290] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T17:25:07.681177] LOG: [CONN] Frame received (59 bytes): 88 31 b8 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 75 e9 24 08 7a cf 9d 32 2a dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b +[2026-02-20T17:25:07.681296] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:07.681329] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:07.681387] LOG: [RX PARSE] RAW Packet (56 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 75 E9 24 08 7A CF 9D 32 2A DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B +[2026-02-20T17:25:07.681417] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:07.681429] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T17:25:07.681454] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xcc, SNR=12.25, RSSI=-72, payload=32 bytes +[2026-02-20T17:25:07.681469] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T17:25:08.487760] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:08.626720] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 31 04 00 00 00 d6 22 00 00 +[2026-02-20T17:25:08.626847] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:08.626867] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:25:09.874123] LOG: [CONN] Frame received (51 bytes): 88 2f b9 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 +[2026-02-20T17:25:09.874248] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:09.874285] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:09.874347] LOG: [RX PARSE] RAW Packet (48 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 +[2026-02-20T17:25:09.874363] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:09.874380] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T17:25:09.874405] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=24 bytes +[2026-02-20T17:25:09.874425] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T17:25:10.414359] LOG: [CONN] Frame received (51 bytes): 88 32 b9 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7e cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 +[2026-02-20T17:25:10.414501] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:10.414637] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:10.414697] LOG: [RX PARSE] RAW Packet (48 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 +[2026-02-20T17:25:10.414713] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:10.414731] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T17:25:10.414757] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xcc, SNR=12.5, RSSI=-71, payload=24 bytes +[2026-02-20T17:25:10.414771] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T17:25:10.757695] LOG: [CONN] Frame received (55 bytes): 88 2f b9 15 14 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 75 24 5f 53 7e 2a dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d +[2026-02-20T17:25:10.757974] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:10.758007] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:10.758119] LOG: [RX PARSE] RAW Packet (52 bytes): 15 14 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 75 24 5F 53 7E 2A DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D +[2026-02-20T17:25:10.758136] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:10.758152] LOG: [RX PARSE] Path length offset: 1, Path length: 20 +[2026-02-20T17:25:10.758179] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=20, firstHop=0x8b, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=30 bytes +[2026-02-20T17:25:10.758194] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=20 +[2026-02-20T17:25:11.163067] LOG: [CONN] Frame received (56 bytes): 88 30 b8 15 15 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 75 24 5f 53 7e 2a dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d +[2026-02-20T17:25:11.163203] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:11.163232] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:11.163291] LOG: [RX PARSE] RAW Packet (53 bytes): 15 15 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 75 24 5F 53 7E 2A DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D +[2026-02-20T17:25:11.163306] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:11.163321] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T17:25:11.163344] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x8b, lastHop=0xcc, SNR=12.0, RSSI=-72, payload=30 bytes +[2026-02-20T17:25:11.163358] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T17:25:11.427979] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:25:11.428103] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:25:13.487568] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:13.636351] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:13.636470] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:13.636492] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:18.487021] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:18.646492] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:18.646609] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:18.646620] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:23.487645] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:23.656766] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:23.656890] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:23.656911] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:26.430179] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:25:26.432454] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:25:27.102344] LOG: [APP] App resumed from background +[2026-02-20T17:25:28.486764] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:28.546103] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 30 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:28.546192] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:28.546223] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:25:29.658674] LOG: [CONN] Frame received (108 bytes): 88 30 b8 15 04 01 7a 7e dd 11 19 8d bf c6 7d 08 bb 7a 45 f5 92 32 cc 23 54 36 99 6e bf 07 8b 6c d6 39 82 d5 09 9f cf 33 de 18 ae ab 4f d6 3e 7a 71 30 90 ca e2 fe 77 08 c5 c1 18 7b 7f ef be fa 54 35 11 b6 45 7e b9 74 41 31 7a c1 a4 fa 46 15 1a 71 a1 ff f0 b4 29 03 cb 80 75 db f5 da 10 79 aa 03 9a 69 a7 d3 a3 ba fe 02 f1 c6 +[2026-02-20T17:25:29.658934] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:29.659104] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:29.659196] LOG: [RX PARSE] RAW Packet (105 bytes): 15 04 01 7A 7E DD 11 19 8D BF C6 7D 08 BB 7A 45 F5 92 32 CC 23 54 36 99 6E BF 07 8B 6C D6 39 82 D5 09 9F CF 33 DE 18 AE AB 4F D6 3E 7A 71 30 90 CA E2 FE 77 08 C5 C1 18 7B 7F EF BE FA 54 35 11 B6 45 7E B9 74 41 31 7A C1 A4 FA 46 15 1A 71 A1 FF F0 B4 29 03 CB 80 75 DB F5 DA 10 79 AA 03 9A 69 A7 D3 A3 BA FE 02 F1 C6 +[2026-02-20T17:25:29.659220] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:29.659304] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T17:25:29.660089] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x01, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=99 bytes +[2026-02-20T17:25:29.660146] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T17:25:29.660665] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T17:25:29.660678] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T17:25:29.660690] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T17:25:31.638278] LOG: [CONN] Frame received (109 bytes): 88 2f b8 15 05 01 7a 7e dd cc 11 19 8d bf c6 7d 08 bb 7a 45 f5 92 32 cc 23 54 36 99 6e bf 07 8b 6c d6 39 82 d5 09 9f cf 33 de 18 ae ab 4f d6 3e 7a 71 30 90 ca e2 fe 77 08 c5 c1 18 7b 7f ef be fa 54 35 11 b6 45 7e b9 74 41 31 7a c1 a4 fa 46 15 1a 71 a1 ff f0 b4 29 03 cb 80 75 db f5 da 10 79 aa 03 9a 69 a7 d3 a3 ba fe 02 f1 c6 +[2026-02-20T17:25:31.638414] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:31.638459] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:31.638651] LOG: [RX PARSE] RAW Packet (106 bytes): 15 05 01 7A 7E DD CC 11 19 8D BF C6 7D 08 BB 7A 45 F5 92 32 CC 23 54 36 99 6E BF 07 8B 6C D6 39 82 D5 09 9F CF 33 DE 18 AE AB 4F D6 3E 7A 71 30 90 CA E2 FE 77 08 C5 C1 18 7B 7F EF BE FA 54 35 11 B6 45 7E B9 74 41 31 7A C1 A4 FA 46 15 1A 71 A1 FF F0 B4 29 03 CB 80 75 DB F5 DA 10 79 AA 03 9A 69 A7 D3 A3 BA FE 02 F1 C6 +[2026-02-20T17:25:31.638667] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:31.638679] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T17:25:31.638735] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x01, lastHop=0xcc, SNR=11.75, RSSI=-72, payload=99 bytes +[2026-02-20T17:25:31.638750] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T17:25:33.487078] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:25:33.487967] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:33.650447] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:25:33.650623] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:25:33.650701] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:25:33.650801] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T17:25:33.705385] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 2f 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:33.705443] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:33.705451] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:38.487046] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:38.566907] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 2f 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:38.567029] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:38.567057] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:25:41.428109] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:25:41.428251] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:25:43.486951] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:43.608947] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 2f 04 00 00 00 d7 22 00 00 +[2026-02-20T17:25:43.609081] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:43.609179] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:25:46.743942] LOG: [CONN] Frame received (124 bytes): 88 33 b7 15 04 1f 7e 2a dd 72 5f 69 23 41 93 cc 75 8f 30 17 3a 4f 17 74 c9 d8 c9 ec 3c 83 dc 91 5b 64 07 a7 6e 96 80 67 c6 9b cb 8d e1 b5 de 68 51 1c 2b 23 63 07 c5 47 6e a0 15 df ea c1 67 bf d5 17 cf 5b 10 5a 55 24 61 cb f1 8b d9 c6 83 04 fb 89 45 6b 00 ad 85 1c c2 26 15 24 8c 15 1a 6d 96 53 93 b8 77 4c 0a a6 b5 7e a1 91 1d 26 87 98 de 9e 95 28 6e f2 6e 2d 75 ba 23 b8 +[2026-02-20T17:25:46.743989] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:46.744026] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:46.744076] LOG: [RX PARSE] RAW Packet (121 bytes): 15 04 1F 7E 2A DD 72 5F 69 23 41 93 CC 75 8F 30 17 3A 4F 17 74 C9 D8 C9 EC 3C 83 DC 91 5B 64 07 A7 6E 96 80 67 C6 9B CB 8D E1 B5 DE 68 51 1C 2B 23 63 07 C5 47 6E A0 15 DF EA C1 67 BF D5 17 CF 5B 10 5A 55 24 61 CB F1 8B D9 C6 83 04 FB 89 45 6B 00 AD 85 1C C2 26 15 24 8C 15 1A 6D 96 53 93 B8 77 4C 0A A6 B5 7E A1 91 1D 26 87 98 DE 9E 95 28 6E F2 6E 2D 75 BA 23 B8 +[2026-02-20T17:25:46.744139] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:46.744145] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T17:25:46.744192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x1f, lastHop=0xdd, SNR=12.75, RSSI=-73, payload=115 bytes +[2026-02-20T17:25:46.744199] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T17:25:47.618583] LOG: [APP] App resumed from background +[2026-02-20T17:25:47.702006] LOG: [CONN] Frame received (125 bytes): 88 31 ba 15 05 1f 7e 2a dd cc 72 5f 69 23 41 93 cc 75 8f 30 17 3a 4f 17 74 c9 d8 c9 ec 3c 83 dc 91 5b 64 07 a7 6e 96 80 67 c6 9b cb 8d e1 b5 de 68 51 1c 2b 23 63 07 c5 47 6e a0 15 df ea c1 67 bf d5 17 cf 5b 10 5a 55 24 61 cb f1 8b d9 c6 83 04 fb 89 45 6b 00 ad 85 1c c2 26 15 24 8c 15 1a 6d 96 53 93 b8 77 4c 0a a6 b5 7e a1 91 1d 26 87 98 de 9e 95 28 6e f2 6e 2d 75 ba 23 b8 +[2026-02-20T17:25:47.702059] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:47.702075] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:47.702109] LOG: [RX PARSE] RAW Packet (122 bytes): 15 05 1F 7E 2A DD CC 72 5F 69 23 41 93 CC 75 8F 30 17 3A 4F 17 74 C9 D8 C9 EC 3C 83 DC 91 5B 64 07 A7 6E 96 80 67 C6 9B CB 8D E1 B5 DE 68 51 1C 2B 23 63 07 C5 47 6E A0 15 DF EA C1 67 BF D5 17 CF 5B 10 5A 55 24 61 CB F1 8B D9 C6 83 04 FB 89 45 6B 00 AD 85 1C C2 26 15 24 8C 15 1A 6D 96 53 93 B8 77 4C 0A A6 B5 7E A1 91 1D 26 87 98 DE 9E 95 28 6E F2 6E 2D 75 BA 23 B8 +[2026-02-20T17:25:47.702113] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:47.702117] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T17:25:47.702123] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-70, payload=115 bytes +[2026-02-20T17:25:47.702127] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T17:25:48.487006] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:48.645542] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff ba 31 04 00 00 00 d8 22 00 00 +[2026-02-20T17:25:48.645643] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:48.645655] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T17:25:49.294478] LOG: [CONN] Frame received (51 bytes): 88 31 b9 15 15 4d 13 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e dd 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 +[2026-02-20T17:25:49.294789] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:49.294826] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:49.294878] LOG: [RX PARSE] RAW Packet (48 bytes): 15 15 4D 13 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E DD 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 +[2026-02-20T17:25:49.294898] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:49.294909] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T17:25:49.294991] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x4d, lastHop=0xdd, SNR=12.25, RSSI=-71, payload=25 bytes +[2026-02-20T17:25:49.295006] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T17:25:49.955720] LOG: [CONN] Frame received (51 bytes): 88 2f ba 15 15 4d 13 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e cc 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 +[2026-02-20T17:25:49.955871] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:49.955909] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:49.955959] LOG: [RX PARSE] RAW Packet (48 bytes): 15 15 4D 13 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 +[2026-02-20T17:25:49.955974] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:49.955989] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T17:25:49.956012] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x4d, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=25 bytes +[2026-02-20T17:25:49.956041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T17:25:52.086269] LOG: [CONN] Frame received (49 bytes): 88 30 b8 15 0a 4d 13 c7 7e 75 20 20 53 86 dd 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 a3 05 f5 00 77 28 d5 11 71 +[2026-02-20T17:25:52.086335] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:52.086388] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:52.086695] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0A 4D 13 C7 7E 75 20 20 53 86 DD 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 A3 05 F5 00 77 28 D5 11 71 +[2026-02-20T17:25:52.086734] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:52.086837] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T17:25:52.086867] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x4d, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=34 bytes +[2026-02-20T17:25:52.086882] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T17:25:53.375359] LOG: [CONN] Frame received (50 bytes): 88 32 ba 15 0b 4d 13 c7 7e 75 20 20 53 86 dd cc 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 a3 05 f5 00 77 28 d5 11 71 +[2026-02-20T17:25:53.375622] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:25:53.375657] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:25:53.375716] LOG: [RX PARSE] RAW Packet (47 bytes): 15 0B 4D 13 C7 7E 75 20 20 53 86 DD CC 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 A3 05 F5 00 77 28 D5 11 71 +[2026-02-20T17:25:53.375732] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:25:53.375742] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T17:25:53.375775] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x4d, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=34 bytes +[2026-02-20T17:25:53.375789] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T17:25:53.486846] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:25:53.567225] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff ba 32 04 00 00 00 d9 22 00 00 +[2026-02-20T17:25:53.567341] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:25:53.567362] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T17:25:56.427822] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:25:56.427963] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:25:56.941329] LOG: [HEARTBEAT] Heartbeat mode disabled +[2026-02-20T17:25:56.941442] LOG: [BACKGROUND] Service not running +[2026-02-20T17:25:56.941481] LOG: [RX LOG] Stopping passive RX wardriving: trigger=disconnect +[2026-02-20T17:25:56.941501] LOG: [RX BATCH] Flushing all repeaters, trigger=disconnect, active_repeaters=0 +[2026-02-20T17:25:56.941504] LOG: [RX BATCH] No repeaters to flush +[2026-02-20T17:25:56.941509] LOG: [API QUEUE] Timers stopped on disconnect +[2026-02-20T17:25:56.943876] LOG: [APP] Releasing API session +[2026-02-20T17:25:57.657158] LOG: [API] POST /wardrive-api.php/auth +[2026-02-20T17:25:57.657193] LOG: [API] Request: {"reason":"disconnect"} +[2026-02-20T17:25:57.657210] LOG: [API] Response (200) in 0.71s: {"success":true,"disconnected":true} +[2026-02-20T17:25:57.657216] LOG: [API] Session cleared +[2026-02-20T17:25:57.657221] LOG: [APP] API session released successfully +[2026-02-20T17:25:57.827724] LOG: [CHANNEL] Deleting channel at index 2 +[2026-02-20T17:25:57.828007] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:25:57.828012] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:25:57.828030] LOG: [CONN] Received OK response +[2026-02-20T17:25:57.884539] LOG: [CHANNEL] Channel deleted successfully +[2026-02-20T17:25:57.884600] LOG: [UNIFIED RX] Disposing unified handler +[2026-02-20T17:25:57.884605] LOG: [UNIFIED RX] Stopping unified RX listening +[2026-02-20T17:25:57.884619] LOG: [UNIFIED RX] ✅ Unified listening stopped +[2026-02-20T17:25:57.884627] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T17:25:57.884630] LOG: [RX LOG] Disposing RX Logger +[2026-02-20T17:25:57.884637] LOG: [CONN] Disconnecting +[2026-02-20T17:25:57.884680] LOG: [CONN] Stopped noise floor polling +[2026-02-20T17:25:57.884697] LOG: [CONN] Stopped battery polling +[2026-02-20T17:25:57.888563] LOG: [BLE] Connection state changed: BluetoothConnectionState.disconnected +[2026-02-20T17:25:57.888624] LOG: [CONN] Step: ConnectionStep.disconnected +[2026-02-20T17:25:57.888643] LOG: [CONN] Disconnected successfully +[2026-02-20T17:25:57.888657] LOG: [HEARTBEAT] Heartbeat mode disabled +[2026-02-20T17:25:57.888660] LOG: [CONN] Heartbeat disabled due to BLE disconnect +[2026-02-20T17:25:57.888689] LOG: [API QUEUE] Timers stopped on disconnect +[2026-02-20T17:25:57.888701] LOG: [CONN] Stopped noise floor polling +[2026-02-20T17:25:57.888706] LOG: [CONN] Stopped battery polling +[2026-02-20T17:25:57.888710] LOG: [DISC] Stopping discovery mode +[2026-02-20T17:25:57.888736] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:25:57.888751] LOG: [CHANNEL] Clearing regional channels +[2026-02-20T17:25:57.888774] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:25:57.891285] LOG: [APP] Saved preferences +[2026-02-20T17:59:16.370817] LOG: [GPS SERVICE] Position stream fired: lat=47.33704, lon=-122.22633, accuracy=600.0m +[2026-02-20T17:59:16.371592] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:59:16.371689] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone +[2026-02-20T17:59:16.371699] LOG: [GEOFENCE] checkZoneStatus() called +[2026-02-20T17:59:16.371883] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked +[2026-02-20T17:59:16.371895] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) +[2026-02-20T17:59:16.371929] LOG: [GEOFENCE] Making API call to check zone at 47.33704, -122.22633 (accuracy: 600.0m) +[2026-02-20T17:59:16.373392] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:59:16.425483] LOG: [APP] App resumed from background +[2026-02-20T17:59:16.767394] ERROR: ❌ [API] /wardrive-api.php/status returned HTTP 403 +[2026-02-20T17:59:16.767536] ERROR: ❌ [API] Response body: {"success":false,"reason":"gps_inaccurate","message":"GPS accuracy exceeds 50 meter threshold"} +[2026-02-20T17:59:16.767556] ERROR: ❌ [API] Response headers: {connection: Keep-Alive, access-control-allow-headers: Content-Type, alt-svc: h3=":443"; ma=2592000, h3-29=":443"; ma=2592000, h3-Q050=":443"; ma=2592000, h3-Q046=":443"; ma=2592000, h3-Q043=":443"; ma=2592000, quic=":443"; ma=2592000; v="43,46", keep-alive: timeout=5, max=100, date: Sat, 21 Feb 2026 01:59:16 GMT, access-control-allow-origin: *, vary: Accept-Encoding, content-encoding: gzip, access-control-allow-methods: POST, OPTIONS, content-length: 107, content-type: application/json; charset=UTF-8, server: LiteSpeed} +[2026-02-20T17:59:16.767630] LOG: [API] POST /wardrive-api.php/status +[2026-02-20T17:59:16.767636] LOG: [API] Request: {"lat":47.3370382,"lng":-122.2263281,"accuracy_m":600.0,"ver":"APP-1771555184","timestamp":1771639156} +[2026-02-20T17:59:16.767645] LOG: [API] Response (403) in 0.40s: {"success":false,"reason":"gps_inaccurate","message":"GPS accuracy exceeds 50 meter threshold"} +[2026-02-20T17:59:16.767653] LOG: [GEOFENCE] API response received: valid +[2026-02-20T17:59:16.767665] ERROR: ❌ [GEOFENCE] Zone status check failed: reason=gps_inaccurate, message=GPS accuracy exceeds 50 meter threshold +[2026-02-20T17:59:16.767729] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA +[2026-02-20T17:59:17.016304] LOG: [GPS SERVICE] Position stream fired: lat=47.33792, lon=-122.22475, accuracy=3.8m +[2026-02-20T17:59:17.016387] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone +[2026-02-20T17:59:17.016392] LOG: [GEOFENCE] checkZoneStatus() called +[2026-02-20T17:59:17.016398] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked +[2026-02-20T17:59:17.016403] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) +[2026-02-20T17:59:17.016409] LOG: [GEOFENCE] Making API call to check zone at 47.33792, -122.22475 (accuracy: 3.8m) +[2026-02-20T17:59:17.212738] LOG: [API] POST /wardrive-api.php/status +[2026-02-20T17:59:17.212772] LOG: [API] Request: {"lat":47.337924,"lng":-122.2247485,"accuracy_m":3.7899999618530273,"ver":"APP-1771555184","timestamp":1771639157} +[2026-02-20T17:59:17.212777] LOG: [API] Response (200) in 0.20s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":12,"slots_max":15}} +[2026-02-20T17:59:17.212784] LOG: [GEOFENCE] API response received: valid +[2026-02-20T17:59:17.212924] LOG: [GEOFENCE] In zone: Seattle, US (SEA) +[2026-02-20T17:59:17.212928] LOG: [MAP] Repeaters already loaded for zone: SEA +[2026-02-20T17:59:17.212934] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA +[2026-02-20T17:59:22.567178] LOG: [BLE] Cached device info: MeshCore-Cozmo (F3:16:AF:D8:2B:1E) +[2026-02-20T17:59:22.572753] LOG: [API QUEUE] Restarting batch timer on connect +[2026-02-20T17:59:22.572823] LOG: [APP] Creating new MeshCoreConnection +[2026-02-20T17:59:22.573151] LOG: [CONN] Step: ConnectionStep.bleConnecting +[2026-02-20T17:59:22.573171] LOG: [BLE] Connection attempt 1/3 to F3:16:AF:D8:2B:1E +[2026-02-20T17:59:22.573197] LOG: [BLE] Device reference created +[2026-02-20T17:59:22.573204] LOG: [BLE] Connecting to GATT... +[2026-02-20T17:59:22.883265] LOG: [BLE] GATT connected +[2026-02-20T17:59:23.293548] LOG: [BLE] MTU negotiated: 247 bytes +[2026-02-20T17:59:23.395022] LOG: [BLE] Discovering services... +[2026-02-20T17:59:23.714302] LOG: [BLE] Found 3 services +[2026-02-20T17:59:23.714498] LOG: [BLE] Found MeshCore service +[2026-02-20T17:59:23.714775] LOG: [BLE] Found TX characteristic +[2026-02-20T17:59:23.714832] LOG: [BLE] Found RX characteristic +[2026-02-20T17:59:23.714842] LOG: [BLE] Enabling notifications... +[2026-02-20T17:59:23.802614] LOG: [BLE] Notifications enabled +[2026-02-20T17:59:23.802763] LOG: [BLE] Device name: MeshCore-Cozmo (from scan: true, platformName: ) +[2026-02-20T17:59:23.802784] LOG: [BLE] Connection complete +[2026-02-20T17:59:23.802807] LOG: [CONN] Step: ConnectionStep.protocolHandshake +[2026-02-20T17:59:23.957428] LOG: [CONN] Frame received (79 bytes): 88 2f b4 15 07 96 a4 cd 6c 7e 9b dd 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e ee 2c 47 +[2026-02-20T17:59:23.957582] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:23.958218] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T17:59:23.958239] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T17:59:23.958250] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T17:59:24.303755] LOG: [CONN] Step: ConnectionStep.deviceQuery +[2026-02-20T17:59:24.373471] LOG: [CONN] Frame received (80 bytes): 0d 08 af 28 00 00 00 00 32 39 2d 4a 61 6e 2d 32 30 32 36 00 48 65 6c 74 65 63 20 54 31 31 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 31 2e 31 32 2e 30 2d 65 37 33 38 61 37 34 00 00 00 00 00 +[2026-02-20T17:59:24.373626] LOG: [CONN] Response code: 0x0d (13) +[2026-02-20T17:59:24.373641] LOG: [CONN] Firmware version: 8 +[2026-02-20T17:59:24.373661] LOG: [CONN] Build date: 29-Jan-2026 +[2026-02-20T17:59:24.373678] LOG: [CONN] Manufacturer model: Heltec T114v1.12.0-e738a74 +[2026-02-20T17:59:24.432798] LOG: [CONN] Frame received (63 bytes): 05 01 16 16 f9 92 6e f7 f7 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f a5 eb ab b8 d2 02 0f 1a b9 f8 00 00 00 01 bd e4 0d 00 24 f4 00 00 07 05 43 6f 7a 6d 6f +[2026-02-20T17:59:24.432931] LOG: [CONN] Response code: 0x05 (5) +[2026-02-20T17:59:24.432975] LOG: [CONN] SelfInfo received: name="Cozmo", publicKey=F9926EF7F78C5689... +[2026-02-20T17:59:24.433015] LOG: [CONN] Public key acquired: F9926EF7F78C5689... +[2026-02-20T17:59:24.433033] LOG: [CONN] Step: ConnectionStep.powerConfiguration +[2026-02-20T17:59:24.433089] LOG: [CONN] Device identified: Heltec T114 (reports 0.3W / 22dBm) +[2026-02-20T17:59:24.433108] LOG: [CONN] Step: ConnectionStep.timeSync +[2026-02-20T17:59:24.496928] LOG: [CONN] Step: ConnectionStep.slotAcquisition +[2026-02-20T17:59:24.497060] LOG: [CONN] Requesting API session via geo-auth +[2026-02-20T17:59:24.497112] LOG: [APP] Stage 1: Attempting auth with public_key: F9926EF7F78C5689... +[2026-02-20T17:59:24.500514] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:59:24.500609] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:59:24.500622] LOG: [CONN] Received OK response +[2026-02-20T17:59:24.790589] LOG: [API] POST /wardrive-api.php/auth +[2026-02-20T17:59:24.790689] LOG: [API] Request: {"reason":"connect","who":"Cozmo","ver":"APP-1771555184","power":"0.3w","iata":"SEA","model":"Heltec T114","coords":{"lat":47.337924,"lng":-122.2247485,"accuracy_m":3.7899999618530273,"timestamp":1771639164}} +[2026-02-20T17:59:24.790710] LOG: [API] Response (200) in 0.29s: {"success":true,"tx_allowed":true,"rx_allowed":true,"zone":{"name":"Seattle, US","code":"SEA"},"expires_at":1771639464,"type":"API","debug_mode":0,"enforce_hybrid":false,"min_mode_interval":15,"channels":["public","bot","bot-tacoma","olybot","bot-islands","sipesbot"]} +[2026-02-20T17:59:24.790753] LOG: [API] Regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] +[2026-02-20T17:59:24.790785] LOG: [APP] Stage 1 succeeded: authenticated via public_key +[2026-02-20T17:59:24.790796] LOG: [APP] Auth type: API +[2026-02-20T17:59:24.790815] LOG: [CONN] API session acquired successfully (session_id: SEA-20260220-0039) +[2026-02-20T17:59:24.790838] LOG: [CONN] Step: ConnectionStep.channelSetup +[2026-02-20T17:59:24.790850] LOG: [CONN] Creating #wardriving channel +[2026-02-20T17:59:24.790860] LOG: [CHANNEL] Looking up channel: #wardriving +[2026-02-20T17:59:24.790878] LOG: [CONN] getChannel(0) - sending request +[2026-02-20T17:59:24.790905] LOG: [CONN] getChannel bytes: 0x1f 0x00 +[2026-02-20T17:59:24.915217] LOG: [CONN] Frame received (50 bytes): 12 00 50 75 62 6c 69 63 00 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 8b 33 87 e9 c5 cd ea 6a c9 e5 ed ba a1 15 cd 72 +[2026-02-20T17:59:24.915344] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:24.915391] LOG: [CONN] getChannel(1) - sending request +[2026-02-20T17:59:24.915411] LOG: [CONN] getChannel bytes: 0x1f 0x01 +[2026-02-20T17:59:24.972776] LOG: [CONN] Frame received (50 bytes): 12 01 23 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 62 e8 c7 49 22 e1 e3 9e 52 e2 2d 14 7c 9a c0 2f +[2026-02-20T17:59:24.972832] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:24.972841] LOG: [CONN] getChannel(2) - sending request +[2026-02-20T17:59:24.972844] LOG: [CONN] getChannel bytes: 0x1f 0x02 +[2026-02-20T17:59:25.031100] LOG: [CONN] Frame received (50 bytes): 12 02 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.031130] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.031136] LOG: [CHANNEL] Found empty slot at index 2 +[2026-02-20T17:59:25.031138] LOG: [CONN] getChannel(3) - sending request +[2026-02-20T17:59:25.031141] LOG: [CONN] getChannel bytes: 0x1f 0x03 +[2026-02-20T17:59:25.091174] LOG: [CONN] Frame received (50 bytes): 12 03 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.091200] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.091205] LOG: [CONN] getChannel(4) - sending request +[2026-02-20T17:59:25.091208] LOG: [CONN] getChannel bytes: 0x1f 0x04 +[2026-02-20T17:59:25.151498] LOG: [CONN] Frame received (50 bytes): 12 04 23 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 83 c8 b0 19 97 65 42 65 93 8d a8 76 5c bc 7d b9 +[2026-02-20T17:59:25.151556] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.151569] LOG: [CONN] getChannel(5) - sending request +[2026-02-20T17:59:25.151573] LOG: [CONN] getChannel bytes: 0x1f 0x05 +[2026-02-20T17:59:25.212670] LOG: [CONN] Frame received (50 bytes): 12 05 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.212717] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.212729] LOG: [CONN] getChannel(6) - sending request +[2026-02-20T17:59:25.212734] LOG: [CONN] getChannel bytes: 0x1f 0x06 +[2026-02-20T17:59:25.272269] LOG: [CONN] Frame received (50 bytes): 12 06 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.272359] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.272513] LOG: [CONN] getChannel(7) - sending request +[2026-02-20T17:59:25.272518] LOG: [CONN] getChannel bytes: 0x1f 0x07 +[2026-02-20T17:59:25.331240] LOG: [CONN] Frame received (50 bytes): 12 07 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.331303] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.331315] LOG: [CONN] getChannel(8) - sending request +[2026-02-20T17:59:25.331322] LOG: [CONN] getChannel bytes: 0x1f 0x08 +[2026-02-20T17:59:25.391107] LOG: [CONN] Frame received (50 bytes): 12 08 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.391154] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.391164] LOG: [CONN] getChannel(9) - sending request +[2026-02-20T17:59:25.391170] LOG: [CONN] getChannel bytes: 0x1f 0x09 +[2026-02-20T17:59:25.451929] LOG: [CONN] Frame received (50 bytes): 12 09 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.451977] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.451987] LOG: [CONN] getChannel(10) - sending request +[2026-02-20T17:59:25.451995] LOG: [CONN] getChannel bytes: 0x1f 0x0a +[2026-02-20T17:59:25.511120] LOG: [CONN] Frame received (50 bytes): 12 0a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.511158] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.511168] LOG: [CONN] getChannel(11) - sending request +[2026-02-20T17:59:25.511174] LOG: [CONN] getChannel bytes: 0x1f 0x0b +[2026-02-20T17:59:25.572632] LOG: [CONN] Frame received (50 bytes): 12 0b 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.572670] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.572678] LOG: [CONN] getChannel(12) - sending request +[2026-02-20T17:59:25.572684] LOG: [CONN] getChannel bytes: 0x1f 0x0c +[2026-02-20T17:59:25.631418] LOG: [CONN] Frame received (80 bytes): 88 2d c2 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e ee 2c 47 +[2026-02-20T17:59:25.631452] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:25.632338] LOG: [CONN] Frame received (50 bytes): 12 0c 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.632364] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.632373] LOG: [CONN] getChannel(13) - sending request +[2026-02-20T17:59:25.632379] LOG: [CONN] getChannel bytes: 0x1f 0x0d +[2026-02-20T17:59:25.691078] LOG: [CONN] Frame received (50 bytes): 12 0d 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.691112] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.691122] LOG: [CONN] getChannel(14) - sending request +[2026-02-20T17:59:25.691128] LOG: [CONN] getChannel bytes: 0x1f 0x0e +[2026-02-20T17:59:25.752898] LOG: [CONN] Frame received (50 bytes): 12 0e 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.752934] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.752943] LOG: [CONN] getChannel(15) - sending request +[2026-02-20T17:59:25.752949] LOG: [CONN] getChannel bytes: 0x1f 0x0f +[2026-02-20T17:59:25.813005] LOG: [CONN] Frame received (50 bytes): 12 0f 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.813068] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.813123] LOG: [CONN] getChannel(16) - sending request +[2026-02-20T17:59:25.813133] LOG: [CONN] getChannel bytes: 0x1f 0x10 +[2026-02-20T17:59:25.871311] LOG: [CONN] Frame received (50 bytes): 12 10 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.871355] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.871370] LOG: [CONN] getChannel(17) - sending request +[2026-02-20T17:59:25.871377] LOG: [CONN] getChannel bytes: 0x1f 0x11 +[2026-02-20T17:59:25.931176] LOG: [CONN] Frame received (50 bytes): 12 11 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.931236] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.931249] LOG: [CONN] getChannel(18) - sending request +[2026-02-20T17:59:25.931255] LOG: [CONN] getChannel bytes: 0x1f 0x12 +[2026-02-20T17:59:25.991677] LOG: [CONN] Frame received (50 bytes): 12 12 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:25.991736] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:25.991749] LOG: [CONN] getChannel(19) - sending request +[2026-02-20T17:59:25.991759] LOG: [CONN] getChannel bytes: 0x1f 0x13 +[2026-02-20T17:59:26.051209] LOG: [CONN] Frame received (50 bytes): 12 13 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.051268] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.051278] LOG: [CONN] getChannel(20) - sending request +[2026-02-20T17:59:26.051287] LOG: [CONN] getChannel bytes: 0x1f 0x14 +[2026-02-20T17:59:26.111176] LOG: [CONN] Frame received (50 bytes): 12 14 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.111222] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.111232] LOG: [CONN] getChannel(21) - sending request +[2026-02-20T17:59:26.111240] LOG: [CONN] getChannel bytes: 0x1f 0x15 +[2026-02-20T17:59:26.171125] LOG: [CONN] Frame received (50 bytes): 12 15 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.171173] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.171182] LOG: [CONN] getChannel(22) - sending request +[2026-02-20T17:59:26.171190] LOG: [CONN] getChannel bytes: 0x1f 0x16 +[2026-02-20T17:59:26.231216] LOG: [CONN] Frame received (50 bytes): 12 16 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.231260] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.231270] LOG: [CONN] getChannel(23) - sending request +[2026-02-20T17:59:26.231279] LOG: [CONN] getChannel bytes: 0x1f 0x17 +[2026-02-20T17:59:26.292831] LOG: [CONN] Frame received (50 bytes): 12 17 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.292850] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.292867] LOG: [CONN] getChannel(24) - sending request +[2026-02-20T17:59:26.292874] LOG: [CONN] getChannel bytes: 0x1f 0x18 +[2026-02-20T17:59:26.351274] LOG: [CONN] Frame received (50 bytes): 12 18 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.351335] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.351347] LOG: [CONN] getChannel(25) - sending request +[2026-02-20T17:59:26.351356] LOG: [CONN] getChannel bytes: 0x1f 0x19 +[2026-02-20T17:59:26.412775] LOG: [CONN] Frame received (50 bytes): 12 19 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.412830] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.412841] LOG: [CONN] getChannel(26) - sending request +[2026-02-20T17:59:26.412849] LOG: [CONN] getChannel bytes: 0x1f 0x1a +[2026-02-20T17:59:26.471278] LOG: [CONN] Frame received (50 bytes): 12 1a 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.471339] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.471351] LOG: [CONN] getChannel(27) - sending request +[2026-02-20T17:59:26.471360] LOG: [CONN] getChannel bytes: 0x1f 0x1b +[2026-02-20T17:59:26.531374] LOG: [CONN] Frame received (50 bytes): 12 1b 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.531429] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.531440] LOG: [CONN] getChannel(28) - sending request +[2026-02-20T17:59:26.531448] LOG: [CONN] getChannel bytes: 0x1f 0x1c +[2026-02-20T17:59:26.621205] LOG: [CONN] Frame received (50 bytes): 12 1c 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.621259] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.621272] LOG: [CONN] getChannel(29) - sending request +[2026-02-20T17:59:26.621279] LOG: [CONN] getChannel bytes: 0x1f 0x1d +[2026-02-20T17:59:26.682319] LOG: [CONN] Frame received (50 bytes): 12 1d 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.682377] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.682963] LOG: [CONN] getChannel(30) - sending request +[2026-02-20T17:59:26.682972] LOG: [CONN] getChannel bytes: 0x1f 0x1e +[2026-02-20T17:59:26.741460] LOG: [CONN] Frame received (50 bytes): 12 1e 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.741511] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.741523] LOG: [CONN] getChannel(31) - sending request +[2026-02-20T17:59:26.741529] LOG: [CONN] getChannel bytes: 0x1f 0x1f +[2026-02-20T17:59:26.801319] LOG: [CONN] Frame received (50 bytes): 12 1f 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.801401] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.801414] LOG: [CONN] getChannel(32) - sending request +[2026-02-20T17:59:26.801420] LOG: [CONN] getChannel bytes: 0x1f 0x20 +[2026-02-20T17:59:26.864411] LOG: [CONN] Frame received (50 bytes): 12 20 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.864472] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.864485] LOG: [CONN] getChannel(33) - sending request +[2026-02-20T17:59:26.864492] LOG: [CONN] getChannel bytes: 0x1f 0x21 +[2026-02-20T17:59:26.921244] LOG: [CONN] Frame received (50 bytes): 12 21 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.921300] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.921314] LOG: [CONN] getChannel(34) - sending request +[2026-02-20T17:59:26.921321] LOG: [CONN] getChannel bytes: 0x1f 0x22 +[2026-02-20T17:59:26.981158] LOG: [CONN] Frame received (50 bytes): 12 22 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:26.981213] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:26.981226] LOG: [CONN] getChannel(35) - sending request +[2026-02-20T17:59:26.981232] LOG: [CONN] getChannel bytes: 0x1f 0x23 +[2026-02-20T17:59:27.041333] LOG: [CONN] Frame received (50 bytes): 12 23 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:27.041393] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:27.041404] LOG: [CONN] getChannel(36) - sending request +[2026-02-20T17:59:27.041412] LOG: [CONN] getChannel bytes: 0x1f 0x24 +[2026-02-20T17:59:27.102591] LOG: [CONN] Frame received (50 bytes): 12 24 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:27.102652] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:27.102868] LOG: [CONN] getChannel(37) - sending request +[2026-02-20T17:59:27.102877] LOG: [CONN] getChannel bytes: 0x1f 0x25 +[2026-02-20T17:59:27.161151] LOG: [CONN] Frame received (50 bytes): 12 25 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:27.161221] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:27.161231] LOG: [CONN] getChannel(38) - sending request +[2026-02-20T17:59:27.161238] LOG: [CONN] getChannel bytes: 0x1f 0x26 +[2026-02-20T17:59:27.221472] LOG: [CONN] Frame received (50 bytes): 12 26 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:27.221532] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:27.221545] LOG: [CONN] getChannel(39) - sending request +[2026-02-20T17:59:27.221553] LOG: [CONN] getChannel bytes: 0x1f 0x27 +[2026-02-20T17:59:27.281865] LOG: [CONN] Frame received (50 bytes): 12 27 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2026-02-20T17:59:27.281927] LOG: [CONN] Response code: 0x12 (18) +[2026-02-20T17:59:27.281944] LOG: [CONN] getChannel(40) - sending request +[2026-02-20T17:59:27.281953] LOG: [CONN] getChannel bytes: 0x1f 0x28 +[2026-02-20T17:59:27.340789] LOG: [CONN] Frame received (2 bytes): 01 02 +[2026-02-20T17:59:27.340842] LOG: [CONN] Response code: 0x01 (1) +[2026-02-20T17:59:27.340846] LOG: [CONN] Received ERR response (error code: 2) +[2026-02-20T17:59:27.340878] LOG: [CHANNEL] Scan stopped at channel 40 (error: Exception: Command error (code 2)) +[2026-02-20T17:59:27.340881] LOG: [CHANNEL] #wardriving not found in 40 channels, creating at index 2 +[2026-02-20T17:59:27.340895] LOG: [CRYPTO] Deriving channel key for: #wardriving +[2026-02-20T17:59:27.340949] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.400580] LOG: [CHANNEL] Channel #wardriving created successfully at index 2 +[2026-02-20T17:59:27.400641] LOG: [CONN] Channel ready: #wardriving (CH:2) +[2026-02-20T17:59:27.400647] LOG: [CONN] Step: ConnectionStep.gpsInit +[2026-02-20T17:59:27.400654] LOG: [CONN] Step: ConnectionStep.connected +[2026-02-20T17:59:27.400657] LOG: [CONN] Connection workflow complete +[2026-02-20T17:59:27.400794] LOG: [APP] Device public key stored: F9926EF7F78C5689... +[2026-02-20T17:59:27.400799] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:59:27.400812] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:59:27.401053] LOG: [APP] Saved last connected device: Cozmo +[2026-02-20T17:59:27.601700] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:59:27.601836] LOG: [CONN] Started battery polling (30s interval) +[2026-02-20T17:59:27.601846] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:27.601859] LOG: [CONN] Started noise floor polling (5s interval) +[2026-02-20T17:59:27.601898] LOG: [MODEL] Device recognized: Heltec T114 - reporting 0.3W in API calls +[2026-02-20T17:59:27.601904] LOG: [APP] Creating unified RX handler +[2026-02-20T17:59:27.601915] LOG: [APP] TxTracker.carpeaterPrefix set to CC +[2026-02-20T17:59:27.601917] LOG: [APP] TxTracker.onCarpeaterDrop callback SET +[2026-02-20T17:59:27.601934] LOG: [APP] PacketValidator configured with 1 channels: Public +[2026-02-20T17:59:27.601937] LOG: [UNIFIED RX] Starting unified RX listening +[2026-02-20T17:59:27.601941] LOG: [UNIFIED RX] ✅ Unified listening started successfully +[2026-02-20T17:59:27.601945] LOG: [APP] Unified RX handler created and listening +[2026-02-20T17:59:27.602092] LOG: [CHANNEL] Setting regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] +[2026-02-20T17:59:27.602099] LOG: [CRYPTO] Deriving channel key for: #wardriving +[2026-02-20T17:59:27.602119] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602127] LOG: [CHANNEL] Added: #wardriving -> hash=129 +[2026-02-20T17:59:27.602130] LOG: [CRYPTO] Deriving channel key for: #bot +[2026-02-20T17:59:27.602137] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602141] LOG: [CHANNEL] Added: #bot -> hash=202 +[2026-02-20T17:59:27.602145] LOG: [CRYPTO] Deriving channel key for: #bot-tacoma +[2026-02-20T17:59:27.602149] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602155] LOG: [CHANNEL] Added: #bot-tacoma -> hash=5 +[2026-02-20T17:59:27.602157] LOG: [CRYPTO] Deriving channel key for: #olybot +[2026-02-20T17:59:27.602163] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602168] LOG: [CHANNEL] Added: #olybot -> hash=221 +[2026-02-20T17:59:27.602170] LOG: [CRYPTO] Deriving channel key for: #bot-islands +[2026-02-20T17:59:27.602175] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602180] LOG: [CHANNEL] Added: #bot-islands -> hash=183 +[2026-02-20T17:59:27.602183] LOG: [CRYPTO] Deriving channel key for: #sipesbot +[2026-02-20T17:59:27.602187] LOG: [CRYPTO] Channel key derived successfully (16 bytes) +[2026-02-20T17:59:27.602192] LOG: [CHANNEL] Added: #sipesbot -> hash=97 +[2026-02-20T17:59:27.602194] LOG: [CHANNEL] Total channels: 7 +[2026-02-20T17:59:27.602204] LOG: [APP] Regional channels configured: [#bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot] +[2026-02-20T17:59:27.602209] LOG: [UNIFIED RX] Validator updated with new channel configuration +[2026-02-20T17:59:27.602214] LOG: [APP] PacketValidator updated with 7 channels: Public, #wardriving, #bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot +[2026-02-20T17:59:27.602217] LOG: [CONN] No regional scope — using unscoped flood +[2026-02-20T17:59:27.602223] LOG: [HIVE] Opening box "remembered_device"... +[2026-02-20T17:59:27.602350] LOG: [HIVE] Box "remembered_device" opened successfully +[2026-02-20T17:59:27.603545] LOG: [APP] Saved remembered device: MeshCore-Cozmo +[2026-02-20T17:59:27.603552] LOG: [APP] Display name set: "Cozmo" +[2026-02-20T17:59:27.603559] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:59:27.603567] LOG: [APP] Restored antenna preference for "Cozmo": external +[2026-02-20T17:59:27.603570] LOG: [CONN] Connected with full access (TX + RX allowed) +[2026-02-20T17:59:27.603578] LOG: [CONN] Ping validation after connect: PingValidation.tooCloseToLastPing +[2026-02-20T17:59:27.603585] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:59:27.603750] LOG: [APP] Saved preferences +[2026-02-20T17:59:28.710428] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T17:59:28.710772] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T17:59:28.710787] LOG: [CONN] Received OK response +[2026-02-20T17:59:28.711094] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:59:28.711104] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:59:28.711123] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:59:28.711134] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T17:59:28.711498] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2d 07 00 00 00 66 23 00 00 +[2026-02-20T17:59:28.711510] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:28.711524] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:31.198204] LOG: [CONN] Frame received (82 bytes): 88 31 b4 15 0d 96 a4 cd 6c 7e 75 20 20 20 20 53 7e dd 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e +[2026-02-20T17:59:31.198268] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:31.198279] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:31.198298] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0D 96 A4 CD 6C 7E 75 20 20 20 20 53 7E DD 11 98 AB 45 F0 AC 14 FC FB 19 8C 5F 06 2B 4F 6B 0D 92 AC 8F DF 5A 2B AD 80 43 5B 9C CD 35 B8 45 57 C9 A8 3F ED 79 29 A1 E2 65 7F 85 AC 66 DD 27 98 48 35 58 14 CD 23 96 10 52 5A F1 99 80 58 4E +[2026-02-20T17:59:31.198304] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:31.198307] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T17:59:31.198319] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x96, lastHop=0xdd, SNR=12.25, RSSI=-76, payload=64 bytes +[2026-02-20T17:59:31.198326] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T17:59:32.602667] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:32.740705] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 0e 07 00 00 00 66 23 00 00 +[2026-02-20T17:59:32.740751] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:32.740756] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T17:59:35.351227] LOG: [APP] App resumed from background +[2026-02-20T17:59:37.573702] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:59:37.573758] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:59:37.602848] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:37.662852] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 0e 07 00 00 00 66 23 00 00 +[2026-02-20T17:59:37.662918] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:37.662930] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:42.603530] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:42.673170] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 0e 07 00 00 00 66 23 00 00 +[2026-02-20T17:59:42.673293] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:42.673314] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:43.381886] LOG: [CONN] Frame received (86 bytes): 88 2d ae 15 11 b0 fb a6 b8 1f 53 20 20 20 20 c5 26 07 a5 e8 32 dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 a3 9b +[2026-02-20T17:59:43.382044] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:43.382080] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:43.382145] LOG: [RX PARSE] RAW Packet (83 bytes): 15 11 B0 FB A6 B8 1F 53 20 20 20 20 C5 26 07 A5 E8 32 DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 A3 9B +[2026-02-20T17:59:43.382171] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:43.382180] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T17:59:43.382214] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xb0, lastHop=0xdd, SNR=11.25, RSSI=-82, payload=64 bytes +[2026-02-20T17:59:43.382225] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T17:59:44.056430] LOG: [CONN] Frame received (87 bytes): 88 2d d2 15 12 b0 fb a6 b8 1f 53 20 20 20 20 c5 26 07 a5 e8 32 dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 a3 9b +[2026-02-20T17:59:44.056593] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:44.056627] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:44.056724] LOG: [RX PARSE] RAW Packet (84 bytes): 15 12 B0 FB A6 B8 1F 53 20 20 20 20 C5 26 07 A5 E8 32 DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 A3 9B +[2026-02-20T17:59:44.056743] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:44.056760] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T17:59:44.056788] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xb0, lastHop=0xcc, SNR=11.25, RSSI=-46, payload=64 bytes +[2026-02-20T17:59:44.056807] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T17:59:44.549622] LOG: [CONN] Frame received (84 bytes): 88 28 ac 15 11 b0 fb a6 b8 1f 53 20 20 20 20 20 20 53 a5 e8 32 dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 +[2026-02-20T17:59:44.549742] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:44.549764] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:44.549814] LOG: [RX PARSE] RAW Packet (81 bytes): 15 11 B0 FB A6 B8 1F 53 20 20 20 20 20 20 53 A5 E8 32 DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 +[2026-02-20T17:59:44.549884] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:44.549892] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T17:59:44.549924] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xb0, lastHop=0xdd, SNR=10.0, RSSI=-84, payload=62 bytes +[2026-02-20T17:59:44.549935] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T17:59:45.977094] LOG: [CONN] Frame received (85 bytes): 88 2e cc 15 12 b0 fb a6 b8 1f 53 20 20 20 20 20 20 53 a5 e8 32 dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 +[2026-02-20T17:59:45.977267] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:45.977308] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:45.977387] LOG: [RX PARSE] RAW Packet (82 bytes): 15 12 B0 FB A6 B8 1F 53 20 20 20 20 20 20 53 A5 E8 32 DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 +[2026-02-20T17:59:45.977405] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:45.977421] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T17:59:45.977456] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xb0, lastHop=0xcc, SNR=11.5, RSSI=-52, payload=62 bytes +[2026-02-20T17:59:45.977484] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T17:59:47.603198] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:47.683325] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2e 07 00 00 00 67 23 00 00 +[2026-02-20T17:59:47.683452] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:47.683473] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:47.930173] LOG: [CONN] Frame received (87 bytes): 88 2f b6 15 15 b0 fb a6 b8 1f 53 20 20 20 20 20 20 20 53 fc 7a 7e 41 32 2a dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 +[2026-02-20T17:59:47.930441] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:47.930480] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:47.930597] LOG: [RX PARSE] RAW Packet (84 bytes): 15 15 B0 FB A6 B8 1F 53 20 20 20 20 20 20 20 53 FC 7A 7E 41 32 2A DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 +[2026-02-20T17:59:47.930621] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:47.930633] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T17:59:47.930668] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xb0, lastHop=0xdd, SNR=11.75, RSSI=-74, payload=61 bytes +[2026-02-20T17:59:47.930687] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T17:59:49.401465] LOG: [CONN] Frame received (88 bytes): 88 35 cd 15 16 b0 fb a6 b8 1f 53 20 20 20 20 20 20 20 53 fc 7a 7e 41 32 2a dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 +[2026-02-20T17:59:49.401652] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T17:59:49.401686] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T17:59:49.401770] LOG: [RX PARSE] RAW Packet (85 bytes): 15 16 B0 FB A6 B8 1F 53 20 20 20 20 20 20 20 53 FC 7A 7E 41 32 2A DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 +[2026-02-20T17:59:49.401793] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T17:59:49.401810] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T17:59:49.401846] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xb0, lastHop=0xcc, SNR=13.25, RSSI=-51, payload=61 bytes +[2026-02-20T17:59:49.401860] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T17:59:52.573958] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T17:59:52.574112] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T17:59:52.602744] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:52.753327] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 +[2026-02-20T17:59:52.753449] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:52.753470] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:56.036068] LOG: [GPS SERVICE] Position stream fired: lat=47.33788, lon=-122.22497, accuracy=3.9m +[2026-02-20T17:59:56.036178] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T17:59:56.036206] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T17:59:57.603336] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T17:59:57.603539] LOG: [CONN] Fetching noise floor... +[2026-02-20T17:59:57.792015] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T17:59:57.792086] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T17:59:57.792094] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T17:59:57.792104] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T17:59:57.851355] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 +[2026-02-20T17:59:57.851420] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T17:59:57.851428] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T17:59:58.083587] LOG: [SESSION] Checking session validity via heartbeat... +[2026-02-20T17:59:58.645645] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T17:59:58.645673] LOG: [API] Request: {"heartbeat":true,"has_coords":true} +[2026-02-20T17:59:58.645677] LOG: [API] Response (200) in 0.56s: {"success":true,"expires_at":1771639498} +[2026-02-20T17:59:58.645685] LOG: [SESSION] Session is valid (expires_at: 1771639498) +[2026-02-20T17:59:58.645695] LOG: [PING] Starting auto mode: active +[2026-02-20T17:59:58.645698] LOG: [PING] Auto-ping interval set to 30000ms +[2026-02-20T17:59:58.645703] LOG: [PING] Using interval from preferences: 30s (30000ms) +[2026-02-20T17:59:58.645706] LOG: [AUTO] enableAutoPing called (passiveMode=false, hybridMode=false) +[2026-02-20T17:59:58.645708] LOG: [AUTO] Acquiring wake lock for auto mode +[2026-02-20T17:59:58.648180] LOG: [WAKELOCK] Screen wake lock enabled +[2026-02-20T17:59:58.648185] LOG: [ACTIVE MODE] Sending initial auto ping +[2026-02-20T17:59:58.648188] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T17:59:58.648196] LOG: [PING] Auto ping blocked: too close to last ping, scheduling next +[2026-02-20T17:59:58.648199] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T17:59:58.648240] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T17:59:58.648244] LOG: [RX LOG] Starting passive RX wardriving +[2026-02-20T17:59:58.648330] LOG: [GRAPH] Started active noise floor session +[2026-02-20T17:59:58.648335] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T17:59:58.648338] LOG: [HEARTBEAT] Heartbeat mode enabled +[2026-02-20T17:59:58.648342] LOG: [HEARTBEAT] Enabled for active Mode +[2026-02-20T17:59:58.648346] LOG: [BACKGROUND] Starting background service (mode: Active Mode) +[2026-02-20T17:59:58.652557] LOG: [BACKGROUND] Background service started +[2026-02-20T18:00:01.044693] LOG: [GPS SERVICE] Position stream fired: lat=47.33788, lon=-122.22521, accuracy=3.9m +[2026-02-20T18:00:02.602649] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:02.712135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 +[2026-02-20T18:00:02.712187] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:02.712193] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:06.042456] LOG: [GPS SERVICE] Position stream fired: lat=47.33785, lon=-122.22558, accuracy=4.5m +[2026-02-20T18:00:07.573762] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:00:07.573845] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:00:07.602885] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:07.723066] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 +[2026-02-20T18:00:07.723143] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:07.723151] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:10.233255] LOG: [CONN] Frame received (68 bytes): 88 2f ac 15 0c 88 82 b5 ba 56 a1 e3 28 aa cd 7e dd 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 1b 69 +[2026-02-20T18:00:10.233399] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:10.233430] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:10.233499] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:10.233515] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:10.233532] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:00:10.233553] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x88, lastHop=0xdd, SNR=11.75, RSSI=-84, payload=51 bytes +[2026-02-20T18:00:10.233580] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:00:10.233591] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:10.233601] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:10.233665] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:10.233681] LOG: [RX FILTER] Raw packet (65 bytes): 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:10.233699] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 +[2026-02-20T18:00:10.233718] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) +[2026-02-20T18:00:10.233731] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:10.233741] LOG: [RX FILTER] Channel hash: 0x69 +[2026-02-20T18:00:10.233757] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 +[2026-02-20T18:00:10.233843] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:00:10.233855] LOG: [RX LOG] Dropped packet hex: 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:11.052970] LOG: [GPS SERVICE] Position stream fired: lat=47.33781, lon=-122.22599, accuracy=4.6m +[2026-02-20T18:00:11.061132] LOG: [CONN] Frame received (69 bytes): 88 31 cc 15 0d 88 82 b5 ba 56 a1 e3 28 aa cd 7e dd cc 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 1b 69 +[2026-02-20T18:00:11.061202] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:11.061212] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:11.061229] LOG: [RX PARSE] RAW Packet (66 bytes): 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:11.061232] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:11.061236] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:00:11.061243] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x88, lastHop=0xcc, SNR=12.25, RSSI=-52, payload=51 bytes +[2026-02-20T18:00:11.061246] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:00:11.061260] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:11.061262] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:11.061276] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:11.061278] LOG: [RX FILTER] Raw packet (66 bytes): 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:11.061284] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 +[2026-02-20T18:00:11.061287] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:00:11.061291] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:11.061294] LOG: [RX FILTER] Channel hash: 0x69 +[2026-02-20T18:00:11.061297] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 +[2026-02-20T18:00:11.061317] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:00:11.061319] LOG: [RX LOG] Dropped packet hex: 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 +[2026-02-20T18:00:12.604381] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:12.763844] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 07 00 00 00 69 23 00 00 +[2026-02-20T18:00:12.763934] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:12.763945] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:15.838362] LOG: [CONN] Frame received (72 bytes): 88 2e ac 15 12 88 82 b5 ba 56 a1 e3 28 aa cd 7e 53 20 20 20 53 86 dd 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 +[2026-02-20T18:00:15.838437] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:15.838452] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:15.838475] LOG: [RX PARSE] RAW Packet (69 bytes): 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:15.838480] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:15.838485] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:00:15.838495] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x88, lastHop=0xdd, SNR=11.5, RSSI=-84, payload=49 bytes +[2026-02-20T18:00:15.838501] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T18:00:15.838505] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:15.838508] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:15.838542] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:15.838547] LOG: [RX FILTER] Raw packet (69 bytes): 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:15.838553] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 11.5 +[2026-02-20T18:00:15.838558] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) +[2026-02-20T18:00:15.838564] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:15.838567] LOG: [RX FILTER] Channel hash: 0x69 +[2026-02-20T18:00:15.838572] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 +[2026-02-20T18:00:15.838597] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:00:15.838601] LOG: [RX LOG] Dropped packet hex: 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:16.049268] LOG: [GPS SERVICE] Position stream fired: lat=47.33781, lon=-122.22632, accuracy=4.2m +[2026-02-20T18:00:16.995160] LOG: [CONN] Frame received (73 bytes): 88 2e cc 15 13 88 82 b5 ba 56 a1 e3 28 aa cd 7e 53 20 20 20 53 86 dd cc 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 +[2026-02-20T18:00:16.995186] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:16.995207] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:16.995231] LOG: [RX PARSE] RAW Packet (70 bytes): 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:16.995238] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:16.995243] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:00:16.995256] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x88, lastHop=0xcc, SNR=11.5, RSSI=-52, payload=49 bytes +[2026-02-20T18:00:16.995262] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:00:16.995271] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:16.995274] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:16.995298] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:16.995303] LOG: [RX FILTER] Raw packet (70 bytes): 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:16.995311] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 11.5 +[2026-02-20T18:00:16.995317] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:00:16.995322] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:16.995328] LOG: [RX FILTER] Channel hash: 0x69 +[2026-02-20T18:00:16.995332] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 +[2026-02-20T18:00:16.995440] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:00:16.995445] LOG: [RX LOG] Dropped packet hex: 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 +[2026-02-20T18:00:17.602925] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:17.651504] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cc 2e 07 00 00 00 69 23 00 00 +[2026-02-20T18:00:17.651584] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:17.651595] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:00:19.671242] LOG: [APP] App resumed from background +[2026-02-20T18:00:21.038729] LOG: [GPS SERVICE] Position stream fired: lat=47.33779, lon=-122.22648, accuracy=4.0m +[2026-02-20T18:00:22.573991] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:00:22.574081] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:00:22.602900] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:22.668943] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2e 07 00 00 00 69 23 00 00 +[2026-02-20T18:00:22.668991] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:22.669] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:22.759162] LOG: [CONN] Frame received (99 bytes): 88 2f b4 15 0b c7 43 fe 7b df b8 4e 1f 7e 2a dd 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 66 30 f2 77 62 5b +[2026-02-20T18:00:22.759317] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:22.759350] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:22.759447] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0B C7 43 FE 7B DF B8 4E 1F 7E 2A DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B +[2026-02-20T18:00:22.759471] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:22.759482] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:00:22.759510] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xdd, SNR=11.75, RSSI=-76, payload=83 bytes +[2026-02-20T18:00:22.759525] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:00:22.759536] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:22.759552] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:22.759666] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:22.759682] LOG: [RX FILTER] Raw packet (96 bytes): 15 0B C7 43 FE 7B DF B8 4E 1F 7E 2A DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B +[2026-02-20T18:00:22.759704] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 11.75 +[2026-02-20T18:00:22.759726] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) +[2026-02-20T18:00:22.759739] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:22.759749] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:00:22.759768] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:00:22.759781] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:00:22.759796] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:00:22.759908] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:00:22.760119] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40742, -122.51648 [..." +[2026-02-20T18:00:22.760144] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:00:22.760160] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:00:22.760192] LOG: [RX LOG] Packet heard via last hop: DD, SNR=11.75, path_length=11 +[2026-02-20T18:00:22.760204] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:00:22.760220] LOG: [RX BATCH] First observation for repeater DD: SNR=11.75 +[2026-02-20T18:00:22.760242] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:00:22.760261] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:00:22.760286] LOG: [APP] Immediate RX observation: repeater=DD, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:22.760306] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:00:22.760332] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.33779,-122.22648 (batch tracking: 1 repeaters, rxCount: 1) +[2026-02-20T18:00:22.760354] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:00:22.760378] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:22.760827] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:00:22.760840] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:00:22.760857] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:00:24.033582] LOG: [CONN] Frame received (100 bytes): 88 2f cb 15 0c c7 43 fe 7b df b8 4e 1f 7e 2a dd cc 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 66 30 f2 77 62 5b +[2026-02-20T18:00:24.033764] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:24.033797] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:24.033893] LOG: [RX PARSE] RAW Packet (97 bytes): 15 0C C7 43 FE 7B DF B8 4E 1F 7E 2A DD CC 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B +[2026-02-20T18:00:24.033914] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:24.033930] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:00:24.033957] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xc7, lastHop=0xcc, SNR=11.75, RSSI=-53, payload=83 bytes +[2026-02-20T18:00:24.033976] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:00:24.033990] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:24.033999] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:24.034091] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:24.034105] LOG: [RX FILTER] Raw packet (97 bytes): 15 0C C7 43 FE 7B DF B8 4E 1F 7E 2A DD CC 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B +[2026-02-20T18:00:24.034131] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 +[2026-02-20T18:00:24.034145] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) +[2026-02-20T18:00:24.034163] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:24.034174] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:00:24.034185] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:00:24.034202] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:00:24.034213] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:00:24.034322] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:00:24.034557] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40742, -122.51648 [..." +[2026-02-20T18:00:24.034585] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:00:24.034595] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:00:24.034653] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=12 +[2026-02-20T18:00:24.034669] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:00:24.034688] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 +[2026-02-20T18:00:24.034705] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:00:24.034732] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:00:24.034753] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:24.034781] LOG: [APP] Current batch tracking: 1 repeaters: {DD} +[2026-02-20T18:00:24.034801] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.33779,-122.22648 (batch tracking: 2 repeaters, rxCount: 2) +[2026-02-20T18:00:24.034827] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:00:24.034848] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:27.602828] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:00:27.602947] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:27.672044] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:00:27.672123] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:00:27.672132] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:00:27.672142] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:00:27.736416] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 2f 07 00 00 00 6a 23 00 00 +[2026-02-20T18:00:27.736520] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:27.736532] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:28.650574] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:00:28.650708] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:00:28.650723] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:00:28.650763] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:00:28.650801] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.33779, -122.22648 [0.3w]" +[2026-02-20T18:00:28.650814] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:00:28.650821] LOG: [TX LOG] Payload: "@[MapperBot] 47.33779, -122.22648 [0.3w]" +[2026-02-20T18:00:28.650832] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:00:28.650846] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:00:28.650857] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:00:28.650865] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:00:28.650885] LOG: [CONN] Sending ping: @[MapperBot] 47.33779, -122.22648 [0.3w] +[2026-02-20T18:00:28.694272] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:00:28.694370] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:00:28.694386] LOG: [CONN] Received OK response +[2026-02-20T18:00:30.149716] LOG: [CONN] Frame received (73 bytes): 88 31 c8 15 01 cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:00:30.149819] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:30.149840] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:30.149875] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:00:30.149885] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:30.149892] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:00:30.149908] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=67 bytes +[2026-02-20T18:00:30.149915] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:00:30.149924] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:00:30.149931] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-56 +[2026-02-20T18:00:30.149939] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:00:30.149944] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:00:30.149951] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:30.149957] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:30.149964] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:00:31.040357] LOG: [GPS SERVICE] Position stream fired: lat=47.33820, lon=-122.22656, accuracy=4.1m +[2026-02-20T18:00:31.040434] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:00:31.040452] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger +[2026-02-20T18:00:31.040471] LOG: [RX BATCH] Distance check for repeater DD: 45.70m from first observation (threshold=25m) +[2026-02-20T18:00:31.040474] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:00:31.040480] LOG: [RX BATCH] Distance check for repeater CC: 45.70m from first observation (threshold=25m) +[2026-02-20T18:00:31.040482] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:00:31.040485] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:00:31.040490] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:00:31.040495] LOG: [RX BATCH] Posting repeater DD: snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:31.040497] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:00:31.040503] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:31.040508] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 11.75 <= pin 11.75 +[2026-02-20T18:00:31.040514] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 +[2026-02-20T18:00:31.040518] LOG: [APP] Added RX log entry: repeater=DD, snr=11.75, pathLen=11 +[2026-02-20T18:00:31.040531] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:00:31.040547] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:00:31.040550] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:00:31.040553] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:00:31.040556] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:31.040560] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:00:31.040562] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.33779,-122.22648 +[2026-02-20T18:00:31.040566] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 +[2026-02-20T18:00:31.040570] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:00:31.040572] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=12 +[2026-02-20T18:00:31.040603] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:00:31.040607] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement +[2026-02-20T18:00:31.456699] LOG: [CONN] Frame received (74 bytes): 88 2b a4 15 02 cc dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:00:31.456755] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:31.456799] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:31.456868] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 CC DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:00:31.456890] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:31.456901] LOG: [RX PARSE] Path length offset: 1, Path length: 2 +[2026-02-20T18:00:31.456930] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0xcc, lastHop=0xdd, SNR=10.75, RSSI=-92, payload=67 bytes +[2026-02-20T18:00:31.456951] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 +[2026-02-20T18:00:31.456961] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:00:31.456978] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-92 +[2026-02-20T18:00:31.456988] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:00:31.457] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd +[2026-02-20T18:00:31.457015] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:00:31.457028] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:00:31.457039] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:00:31.457056] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:00:31.457069] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:00:31.457164] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:00:31.457298] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... +[2026-02-20T18:00:31.457318] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.33779, -122.22648 [0.3w]" (47 chars) +[2026-02-20T18:00:31.457331] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.33779, -122.22648 [0.3w]" (40 chars) +[2026-02-20T18:00:31.457344] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! +[2026-02-20T18:00:31.457366] LOG: [PING] Repeater echo accepted: first_hop=dd, SNR=null, full_path_length=2 (CARpeater stripped) +[2026-02-20T18:00:31.457379] LOG: [PING] Adding new repeater echo: path=dd, SNR=null, RSSI=null +[2026-02-20T18:00:31.457391] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) +[2026-02-20T18:00:31.457398] LOG: [PING] onEchoReceived callback fired: dd, SNR=null, RSSI=null, isNew=true +[2026-02-20T18:00:31.457409] LOG: [PING] Real-time: Added new repeater dd (SNR: null) - total: 1 +[2026-02-20T18:00:31.457414] LOG: [PING] Calling onEchoReceived callback (callback=SET) +[2026-02-20T18:00:31.457419] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== +[2026-02-20T18:00:31.457427] LOG: [APP] Real-time echo: dd (SNR: null, isNew: true) +[2026-02-20T18:00:31.457431] LOG: [APP] TxLogEntries count: 2 +[2026-02-20T18:00:31.457458] LOG: [APP] Updated TxLogEntry with 1 events (real-time) +[2026-02-20T18:00:31.457465] LOG: [APP] Calling notifyListeners() to update UI +[2026-02-20T18:00:31.457472] LOG: [APP] notifyListeners() completed +[2026-02-20T18:00:31.457476] LOG: [PING] onEchoReceived callback completed +[2026-02-20T18:00:31.457483] LOG: [TX LOG] onEchoReceived callback invoked successfully +[2026-02-20T18:00:31.457489] LOG: [TX LOG] ✅ Echo tracked successfully +[2026-02-20T18:00:31.457558] LOG: [UNIFIED RX] Packet was TX echo, done +[2026-02-20T18:00:31.696341] LOG: [PING] Ping sent successfully +[2026-02-20T18:00:32.280470] LOG: [CONN] Frame received (100 bytes): 88 1f a5 15 12 c7 43 fe 7b f5 17 2b 75 20 20 20 20 20 20 20 75 7e dd 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 +[2026-02-20T18:00:32.280599] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:32.280635] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:32.280701] LOG: [RX PARSE] RAW Packet (97 bytes): 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 +[2026-02-20T18:00:32.280720] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:32.280732] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:00:32.280758] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xc7, lastHop=0xdd, SNR=7.75, RSSI=-91, payload=77 bytes +[2026-02-20T18:00:32.280768] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T18:00:32.280781] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:00:32.280791] LOG: [TX LOG] Processing rx_log entry: SNR=7.75, RSSI=-91 +[2026-02-20T18:00:32.280802] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:00:32.280813] LOG: [TX LOG] ✓ RSSI OK (-91 < -30) +[2026-02-20T18:00:32.280822] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:00:32.280835] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:00:32.280843] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:00:32.280853] LOG: [CRYPTO] Decrypting message (74 bytes) +[2026-02-20T18:00:32.281008] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:32.281037] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:32.281051] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:32.281063] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:32.281128] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:32.281137] LOG: [RX FILTER] Raw packet (97 bytes): 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 +[2026-02-20T18:00:32.281156] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 7.75 +[2026-02-20T18:00:32.281174] LOG: [RX FILTER] ✓ RSSI OK (-91 < -30) +[2026-02-20T18:00:32.281182] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:32.281190] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:00:32.281201] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:00:32.281212] LOG: [RX FILTER] Encrypted message: 74 bytes +[2026-02-20T18:00:32.281219] LOG: [CRYPTO] Decrypting message (74 bytes) +[2026-02-20T18:00:32.281318] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:32.281354] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:32.281455] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) + + +[2026-02-20T18:00:32.281541] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:00:32.281551] LOG: [RX LOG] Dropped packet hex: 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 +[2026-02-20T18:00:32.604726] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:32.778500] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff a5 1f 08 00 00 00 6b 23 00 00 +[2026-02-20T18:00:32.778699] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:32.778722] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:00:33.651677] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) +[2026-02-20T18:00:33.651811] LOG: [TX LOG] Final: dd -> SNR=null, seen=1x +[2026-02-20T18:00:36.061143] LOG: [GPS SERVICE] Position stream fired: lat=47.33870, lon=-122.22656, accuracy=4.0m +[2026-02-20T18:00:36.698769] LOG: [PING] RX listening window ended +[2026-02-20T18:00:36.698855] LOG: [PING] TxTracker collected 1 repeater echoes +[2026-02-20T18:00:36.698886] LOG: [PING] Heard repeater: dd, SNR=null +[2026-02-20T18:00:36.699224] LOG: [GRAPH] Recorded txSuccess event at -120dBm with 1 repeater(s) +[2026-02-20T18:00:36.699289] LOG: [PING] Queued TX entry with heard_repeats: dd(null) +[2026-02-20T18:00:36.699302] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:00:36.699322] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:00:36.699349] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:00:36.699375] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:00:36.705932] LOG: [API QUEUE] TX enqueued: dd(null) (queue size: 1) +[2026-02-20T18:00:37.574178] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:00:37.574358] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:00:37.574367] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:00:37.574376] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:00:37.576167] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue +[2026-02-20T18:00:37.602882] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:37.781496] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff a5 1f 08 00 00 00 6b 23 00 00 +[2026-02-20T18:00:37.781585] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:37.781600] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:38.388030] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:00:38.388090] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:00:38.388108] LOG: [API] Response (200) in 0.81s: {"success":true,"expires_at":1771639538} +[2026-02-20T18:00:38.388122] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:00:38.388139] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:00:38.388655] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:00:38.388674] LOG: [APP] Upload success: +2 items (total: 3) +[2026-02-20T18:00:41.049752] LOG: [GPS SERVICE] Position stream fired: lat=47.33923, lon=-122.22654, accuracy=4.1m +[2026-02-20T18:00:41.719301] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:00:41.719349] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:00:41.719356] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:00:41.985767] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:00:41.985850] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:00:41.985872] LOG: [API] Response (200) in 0.27s: {"success":true,"expires_at":1771639541} +[2026-02-20T18:00:41.985889] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:00:41.985907] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:00:41.986771] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:00:41.986788] LOG: [APP] Upload success: +1 items (total: 4) +[2026-02-20T18:00:42.601774] LOG: [CONN] Frame received (139 bytes): 88 2a 9c 11 09 30 1c 26 ca ab 86 7a 7e dd ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 51 8b 47 66 4e a0 13 6f e6 9b 99 d9 cb e4 c1 6f 27 0a 6f 58 63 0c 10 eb c0 88 0d 1c df 1a d6 d0 9b 3a 74 d7 4b 5d cb 0c a9 df cb ca 02 22 bd a6 cc 54 76 be ed 3b 72 09 b0 ef 8d 80 01 e9 57 65 d4 25 ce 07 92 4c d0 ef 02 28 f5 a8 f8 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 +[2026-02-20T18:00:42.601931] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:42.602035] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:42.602155] LOG: [RX PARSE] RAW Packet (136 bytes): 11 09 30 1C 26 CA AB 86 7A 7E DD CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 +[2026-02-20T18:00:42.602182] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:00:42.602193] LOG: [RX PARSE] Path length offset: 1, Path length: 9 +[2026-02-20T18:00:42.602230] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=9, firstHop=0x30, lastHop=0xdd, SNR=10.5, RSSI=-100, payload=125 bytes +[2026-02-20T18:00:42.602244] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=9 +[2026-02-20T18:00:42.602260] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:42.602269] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:42.602383] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:42.602395] LOG: [RX FILTER] Raw packet (136 bytes): 11 09 30 1C 26 CA AB 86 7A 7E DD CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 +[2026-02-20T18:00:42.602422] LOG: [RX FILTER] Header: 0x11 | PathLength: 9 | SNR: 10.5 +[2026-02-20T18:00:42.602436] LOG: [RX FILTER] ✓ RSSI OK (-100 < -30) +[2026-02-20T18:00:42.602453] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:00:42.602464] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:00:42.602473] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:00:42.602669] LOG: [RX FILTER] ADVERT name extracted: "Salish//Seaforth" (16 chars) +[2026-02-20T18:00:42.602688] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:00:42.602715] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Salish//Seaforth") +[2026-02-20T18:00:42.602738] LOG: [RX LOG] Packet heard via last hop: DD, SNR=10.5, path_length=9 +[2026-02-20T18:00:42.602754] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:00:42.602772] LOG: [RX BATCH] First observation for repeater DD: SNR=10.5 +[2026-02-20T18:00:42.602796] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:00:42.602816] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:00:42.602837] LOG: [APP] Immediate RX observation: repeater=DD, snr=10.5, location=47.33923,-122.22654 +[2026-02-20T18:00:42.602861] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:00:42.602881] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.33923,-122.22654 (batch tracking: 1 repeaters, rxCount: 3) +[2026-02-20T18:00:42.602908] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:00:42.602929] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=10.5, location=47.33923,-122.22654 +[2026-02-20T18:00:42.603476] LOG: [CONN] Frame received (148 bytes): 8a ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 51 8b 47 66 4c d0 ef 02 28 f5 a8 f8 c9 11 99 69 +[2026-02-20T18:00:42.603506] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:00:42.603524] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:00:42.603725] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:42.642486] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 9c 2a 08 00 00 00 6b 23 00 00 +[2026-02-20T18:00:42.642607] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:42.642620] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:43.682908] LOG: [CONN] Frame received (140 bytes): 88 32 c8 11 0a 30 1c 26 ca ab 86 7a 7e dd cc ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 51 8b 47 66 4e a0 13 6f e6 9b 99 d9 cb e4 c1 6f 27 0a 6f 58 63 0c 10 eb c0 88 0d 1c df 1a d6 d0 9b 3a 74 d7 4b 5d cb 0c a9 df cb ca 02 22 bd a6 cc 54 76 be ed 3b 72 09 b0 ef 8d 80 01 e9 57 65 d4 25 ce 07 92 4c d0 ef 02 28 f5 a8 f8 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 +[2026-02-20T18:00:43.683093] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:43.683131] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:43.683252] LOG: [RX PARSE] RAW Packet (137 bytes): 11 0A 30 1C 26 CA AB 86 7A 7E DD CC CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 +[2026-02-20T18:00:43.683279] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:00:43.683295] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:00:43.683327] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=10, firstHop=0x30, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=125 bytes +[2026-02-20T18:00:43.683347] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=10 +[2026-02-20T18:00:43.683360] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:43.683369] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:43.683497] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:43.683510] LOG: [RX FILTER] Raw packet (137 bytes): 11 0A 30 1C 26 CA AB 86 7A 7E DD CC CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 +[2026-02-20T18:00:43.683537] LOG: [RX FILTER] Header: 0x11 | PathLength: 10 | SNR: 12.5 +[2026-02-20T18:00:43.683555] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:00:43.683567] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:00:43.683577] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:00:43.683591] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:00:43.683718] LOG: [RX FILTER] ADVERT name extracted: "Salish//Seaforth" (16 chars) +[2026-02-20T18:00:43.683737] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:00:43.683756] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Salish//Seaforth") +[2026-02-20T18:00:43.683782] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=10 +[2026-02-20T18:00:43.683793] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:00:43.683809] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:00:43.683832] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:00:43.683858] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:00:43.683882] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.33923,-122.22654 +[2026-02-20T18:00:43.683902] LOG: [APP] Current batch tracking: 1 repeaters: {DD} +[2026-02-20T18:00:43.683927] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.33923,-122.22654 (batch tracking: 2 repeaters, rxCount: 4) +[2026-02-20T18:00:43.683948] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:00:43.683972] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.33923,-122.22654 +[2026-02-20T18:00:46.011542] LOG: [GPS SERVICE] Position stream fired: lat=47.33979, lon=-122.22652, accuracy=3.8m +[2026-02-20T18:00:46.011635] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger +[2026-02-20T18:00:46.011647] LOG: [RX BATCH] Distance check for repeater DD: 61.92m from first observation (threshold=25m) +[2026-02-20T18:00:46.011651] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:00:46.011655] LOG: [RX BATCH] Distance check for repeater CC: 61.92m from first observation (threshold=25m) +[2026-02-20T18:00:46.011659] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:00:46.011662] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:00:46.011668] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:00:46.011676] LOG: [RX BATCH] Posting repeater DD: snr=10.5, location=47.33923,-122.22654 +[2026-02-20T18:00:46.011679] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:00:46.011685] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=10.5, location=47.33923,-122.22654 +[2026-02-20T18:00:46.011690] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 10.50 <= pin 10.50 +[2026-02-20T18:00:46.011698] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 +[2026-02-20T18:00:46.011702] LOG: [APP] Added RX log entry: repeater=DD, snr=10.5, pathLen=9 +[2026-02-20T18:00:46.011720] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:00:46.011722] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:00:46.011726] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:00:46.011729] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.33923,-122.22654 +[2026-02-20T18:00:46.011731] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:00:46.011735] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.33923,-122.22654 +[2026-02-20T18:00:46.011738] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:00:46.011743] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:00:46.011747] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=10 +[2026-02-20T18:00:46.011754] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:00:46.011757] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement +[2026-02-20T18:00:46.987935] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:00:47.070320] LOG: [CONN] Frame received (84 bytes): 88 13 98 15 10 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 53 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee +[2026-02-20T18:00:47.070431] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:47.070460] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:47.070659] LOG: [RX PARSE] RAW Packet (81 bytes): 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:47.070671] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:47.070676] LOG: [RX PARSE] Path length offset: 1, Path length: 16 +[2026-02-20T18:00:47.070697] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=16, firstHop=0xcc, lastHop=0xdd, SNR=4.75, RSSI=-104, payload=63 bytes +[2026-02-20T18:00:47.070704] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=16 +[2026-02-20T18:00:47.070714] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:47.070719] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:47.070727] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:00:47.070758] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:47.070766] LOG: [RX FILTER] Raw packet (81 bytes): 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:47.070777] LOG: [RX FILTER] Header: 0x15 | PathLength: 16 | SNR: 4.75 +[2026-02-20T18:00:47.070782] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:00:47.070787] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:47.070796] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:00:47.070802] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:00:47.070808] LOG: [RX FILTER] Encrypted message: 60 bytes +[2026-02-20T18:00:47.070815] LOG: [CRYPTO] Decrypting message (60 bytes) +[2026-02-20T18:00:47.070908] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:47.070934] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:47.071059] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:00:47.071118] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:00:47.071123] LOG: [RX LOG] Dropped packet hex: 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:47.602826] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:47.720687] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 98 13 08 00 00 00 6c 23 00 00 +[2026-02-20T18:00:47.720736] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:47.720748] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:48.581683] LOG: [CONN] Frame received (85 bytes): 88 32 c9 15 11 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 53 7e dd cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee +[2026-02-20T18:00:48.581797] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:00:48.581829] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:00:48.581876] LOG: [RX PARSE] RAW Packet (82 bytes): 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:48.581889] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:00:48.581899] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T18:00:48.581915] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-55, payload=63 bytes +[2026-02-20T18:00:48.581926] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T18:00:48.581934] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:00:48.581940] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:00:48.581951] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:00:48.581994] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:00:48.582001] LOG: [RX FILTER] Raw packet (82 bytes): 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:48.582017] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 12.5 +[2026-02-20T18:00:48.582023] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:00:48.582033] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:00:48.582042] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:00:48.582050] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:00:48.582062] LOG: [RX FILTER] Encrypted message: 60 bytes +[2026-02-20T18:00:48.582072] LOG: [CRYPTO] Decrypting message (60 bytes) +[2026-02-20T18:00:48.582198] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:48.582233] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:00:48.582392] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:00:48.582468] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:00:48.582475] LOG: [RX LOG] Dropped packet hex: 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:00:51.009746] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22649, accuracy=3.8m +[2026-02-20T18:00:52.573857] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:00:52.574011] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:00:52.574028] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:00:52.577913] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue +[2026-02-20T18:00:52.602747] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:52.664682] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 +[2026-02-20T18:00:52.664815] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:52.664834] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:53.104790] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:00:53.104860] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:00:53.104873] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771639552} +[2026-02-20T18:00:53.104890] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:00:53.104905] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:00:53.105199] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:00:53.105212] LOG: [APP] Upload success: +1 items (total: 5) +[2026-02-20T18:00:56.016358] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22592, accuracy=3.8m +[2026-02-20T18:00:57.604878] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:00:57.604990] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:00:57.674493] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:00:57.674664] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:00:57.674690] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:00:57.674707] LOG: [CONN] Battery updated: 4080mV (90%) +[2026-02-20T18:00:57.733654] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 +[2026-02-20T18:00:57.733770] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:00:57.733795] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:00:58.105822] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:01:02.014764] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22478, accuracy=3.8m +[2026-02-20T18:01:02.014855] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:01:02.014919] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:01:02.603191] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:02.743786] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 +[2026-02-20T18:01:02.743894] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:02.743907] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:04.634007] LOG: [CONN] Frame received (77 bytes): 88 2e a3 15 05 75 62 7e 48 dd bb 37 b4 11 87 48 fb 51 fd 9d bc 04 80 2e 73 37 92 eb d6 d4 7c 0e 2b 3c 59 c6 3a 55 95 9a 79 ee 1f 7f 2e 3e 04 da c9 26 0d c5 67 ad 7e 48 58 3e e6 e2 70 a0 01 80 40 37 78 73 42 75 d3 2b 7b ef 81 b1 52 +[2026-02-20T18:01:04.634169] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:04.634197] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:04.634272] LOG: [RX PARSE] RAW Packet (74 bytes): 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:04.634294] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:04.634305] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:01:04.634337] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x75, lastHop=0xdd, SNR=11.5, RSSI=-93, payload=67 bytes +[2026-02-20T18:01:04.634351] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T18:01:04.634367] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:04.634378] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:04.634445] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:04.634457] LOG: [RX FILTER] Raw packet (74 bytes): 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:04.634482] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 11.5 +[2026-02-20T18:01:04.634501] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) +[2026-02-20T18:01:04.634512] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:04.634564] LOG: [RX FILTER] Channel hash: 0xbb +[2026-02-20T18:01:04.634581] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xbb +[2026-02-20T18:01:04.634660] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:01:04.634672] LOG: [RX LOG] Dropped packet hex: 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:05.639186] LOG: [CONN] Frame received (78 bytes): 88 2e c8 15 06 75 62 7e 48 dd cc bb 37 b4 11 87 48 fb 51 fd 9d bc 04 80 2e 73 37 92 eb d6 d4 7c 0e 2b 3c 59 c6 3a 55 95 9a 79 ee 1f 7f 2e 3e 04 da c9 26 0d c5 67 ad 7e 48 58 3e e6 e2 70 a0 01 80 40 37 78 73 42 75 d3 2b 7b ef 81 b1 52 +[2026-02-20T18:01:05.639298] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:05.639320] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:05.639383] LOG: [RX PARSE] RAW Packet (75 bytes): 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:05.639400] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:05.639408] LOG: [RX PARSE] Path length offset: 1, Path length: 6 +[2026-02-20T18:01:05.639428] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=6, firstHop=0x75, lastHop=0xcc, SNR=11.5, RSSI=-56, payload=67 bytes +[2026-02-20T18:01:05.639439] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=6 +[2026-02-20T18:01:05.639450] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:05.639458] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:05.639515] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:05.639524] LOG: [RX FILTER] Raw packet (75 bytes): 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:05.639541] LOG: [RX FILTER] Header: 0x15 | PathLength: 6 | SNR: 11.5 +[2026-02-20T18:01:05.639552] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:01:05.639564] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:05.639573] LOG: [RX FILTER] Channel hash: 0xbb +[2026-02-20T18:01:05.639581] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xbb +[2026-02-20T18:01:05.639644] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:01:05.639653] LOG: [RX LOG] Dropped packet hex: 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 +[2026-02-20T18:01:06.701451] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:01:06.701508] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:01:06.701531] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:01:06.701567] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:01:06.701611] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34012, -122.22478 [0.3w]" +[2026-02-20T18:01:06.701623] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:01:06.701638] LOG: [TX LOG] Payload: "@[MapperBot] 47.34012, -122.22478 [0.3w]" +[2026-02-20T18:01:06.701650] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:01:06.701663] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:01:06.701719] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:01:06.701730] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:01:06.701754] LOG: [CONN] Sending ping: @[MapperBot] 47.34012, -122.22478 [0.3w] +[2026-02-20T18:01:06.881160] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:01:06.881213] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:01:06.881219] LOG: [CONN] Received OK response +[2026-02-20T18:01:07.573618] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:01:07.573730] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:01:07.573734] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:01:07.602900] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:07.693795] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c8 2e 08 00 00 00 6d 23 00 00 +[2026-02-20T18:01:07.693921] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:07.693945] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:01:08.105137] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:01:08.105210] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:01:08.105295] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771639567} +[2026-02-20T18:01:08.105314] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:01:08.105336] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:01:08.108701] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:01:08.108737] LOG: [APP] Upload success: +1 items (total: 6) +[2026-02-20T18:01:08.462751] LOG: [CONN] Frame received (86 bytes): 88 1b 98 15 0e 15 c6 24 a5 fe f7 f5 17 53 7e e8 9b 1b dd 11 42 70 b8 35 2b e7 0f 02 38 d6 c7 5a 35 91 a0 2a 46 dc b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 +[2026-02-20T18:01:08.462810] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:08.462822] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:08.462845] LOG: [RX PARSE] RAW Packet (83 bytes): 15 0E 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:08.462850] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:08.462855] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:01:08.462867] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x15, lastHop=0xdd, SNR=6.75, RSSI=-104, payload=67 bytes +[2026-02-20T18:01:08.462874] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:01:08.462877] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:08.462881] LOG: [TX LOG] Processing rx_log entry: SNR=6.75, RSSI=-104 +[2026-02-20T18:01:08.462885] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:08.462889] LOG: [TX LOG] ✓ RSSI OK (-104 < -30) +[2026-02-20T18:01:08.462894] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x11, expected=0x81 +[2026-02-20T18:01:08.462896] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:01:08.462900] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:08.462904] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:08.462922] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:08.462925] LOG: [RX FILTER] Raw packet (83 bytes): 15 0E 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:08.462931] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 6.75 +[2026-02-20T18:01:08.462935] LOG: [RX FILTER] ✓ RSSI OK (-104 < -30) +[2026-02-20T18:01:08.462938] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:08.462940] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:01:08.462944] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:01:08.462947] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:01:08.462950] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:01:08.462982] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:01:08.463034] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" +[2026-02-20T18:01:08.463043] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:01:08.463046] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:01:08.463056] LOG: [RX LOG] Packet heard via last hop: DD, SNR=6.75, path_length=14 +[2026-02-20T18:01:08.463058] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:01:08.463066] LOG: [RX BATCH] First observation for repeater DD: SNR=6.75 +[2026-02-20T18:01:08.463071] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:01:08.463078] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:01:08.463083] LOG: [APP] Immediate RX observation: repeater=DD, snr=6.75, location=47.34012,-122.22478 +[2026-02-20T18:01:08.463090] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:01:08.463096] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34012,-122.22478 (batch tracking: 1 repeaters, rxCount: 5) +[2026-02-20T18:01:08.463105] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) +[2026-02-20T18:01:08.463110] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=6.75, location=47.34012,-122.22478 +[2026-02-20T18:01:08.469709] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:01:08.469722] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:01:08.469726] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:01:08.470609] LOG: [GPS SERVICE] Position stream fired: lat=47.34015, lon=-122.22369, accuracy=3.8m +[2026-02-20T18:01:08.470640] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:01:08.470647] LOG: [RX BATCH] Distance check for repeater DD: 82.38m from first observation (threshold=25m) +[2026-02-20T18:01:08.470653] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:01:08.470655] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:01:08.470660] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:01:08.470665] LOG: [RX BATCH] Posting repeater DD: snr=6.75, location=47.34012,-122.22478 +[2026-02-20T18:01:08.470668] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:01:08.470673] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=6.75, location=47.34012,-122.22478 +[2026-02-20T18:01:08.470678] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 6.75 <= pin 6.75 +[2026-02-20T18:01:08.470705] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 +[2026-02-20T18:01:08.470709] LOG: [APP] Added RX log entry: repeater=DD, snr=6.75, pathLen=14 +[2026-02-20T18:01:08.470775] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:01:08.470780] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:01:09.019461] LOG: [CONN] Frame received (73 bytes): 88 30 c8 15 01 cc 81 1a 53 67 98 d2 97 e0 c6 b5 0d 2d d5 86 97 e5 ca 5f 28 be 2e b0 27 0e 34 2a 0f ab 24 f9 a7 90 e5 c0 06 e5 a7 4b ec bf 6f e8 d9 da 81 4e 4e 35 60 e4 45 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:01:09.019771] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:09.019844] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:09.019975] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1A 53 67 98 D2 97 E0 C6 B5 0D 2D D5 86 97 E5 CA 5F 28 BE 2E B0 27 0E 34 2A 0F AB 24 F9 A7 90 E5 C0 06 E5 A7 4B EC BF 6F E8 D9 DA 81 4E 4E 35 60 E4 45 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:01:09.019992] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:09.020010] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:01:09.020069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=67 bytes +[2026-02-20T18:01:09.020127] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:01:09.020134] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:09.020142] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-56 +[2026-02-20T18:01:09.020611] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:09.020614] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:01:09.020619] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:09.020622] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:09.020625] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:01:09.600486] LOG: [CONN] Frame received (90 bytes): 88 2b 9d 15 28 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab +[2026-02-20T18:01:09.600576] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:09.600593] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:09.600633] LOG: [RX PARSE] RAW Packet (87 bytes): 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:09.600644] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:09.600650] LOG: [RX PARSE] Path length offset: 1, Path length: 40 +[2026-02-20T18:01:09.600670] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=40, firstHop=0xcc, lastHop=0xdd, SNR=10.75, RSSI=-99, payload=45 bytes +[2026-02-20T18:01:09.600678] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=40 +[2026-02-20T18:01:09.600689] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:09.600695] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-99 +[2026-02-20T18:01:09.600700] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:09.600709] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd +[2026-02-20T18:01:09.600715] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:09.600723] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:01:09.600730] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:01:09.600735] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:01:09.600745] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:09.600837] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:09.600857] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:09.600865] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:09.600875] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:09.600882] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:01:09.600918] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:09.600926] LOG: [RX FILTER] Raw packet (87 bytes): 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:09.600937] LOG: [RX FILTER] Header: 0x15 | PathLength: 40 | SNR: 10.75 +[2026-02-20T18:01:09.600945] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:09.600951] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:09.600956] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:09.600966] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:09.600972] LOG: [RX FILTER] Encrypted message: 42 bytes +[2026-02-20T18:01:09.600979] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:09.601039] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:09.601096] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:09.601164] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) + + +[2026-02-20T18:01:09.601216] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:09.601222] LOG: [RX LOG] Dropped packet hex: 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:09.881967] LOG: [PING] Ping sent successfully +[2026-02-20T18:01:10.130730] LOG: [CONN] Frame received (87 bytes): 88 32 c7 15 0f 15 c6 24 a5 fe f7 f5 17 53 7e e8 9b 1b dd cc 11 42 70 b8 35 2b e7 0f 02 38 d6 c7 5a 35 91 a0 2a 46 dc b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 +[2026-02-20T18:01:10.130819] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:10.130837] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:10.130874] LOG: [RX PARSE] RAW Packet (84 bytes): 15 0F 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD CC 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:10.130882] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:10.130891] LOG: [RX PARSE] Path length offset: 1, Path length: 15 +[2026-02-20T18:01:10.130910] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0x15, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes +[2026-02-20T18:01:10.130919] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 +[2026-02-20T18:01:10.130925] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:10.130930] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-57 +[2026-02-20T18:01:10.130937] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:10.130944] LOG: [TX LOG] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:01:10.130949] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x11, expected=0x81 +[2026-02-20T18:01:10.130956] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:01:10.130962] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:10.130969] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:10.131006] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:10.131012] LOG: [RX FILTER] Raw packet (84 bytes): 15 0F 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD CC 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:10.131023] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 12.5 +[2026-02-20T18:01:10.131030] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:01:10.131037] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:10.131044] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:01:10.131049] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:01:10.131057] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:01:10.131062] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:01:10.131105] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:01:10.131201] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" +[2026-02-20T18:01:10.131215] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:01:10.131220] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:01:10.131236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=15 +[2026-02-20T18:01:10.131241] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:01:10.131251] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:01:10.131259] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:01:10.131306] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:01:10.131330] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.34015,-122.22369 +[2026-02-20T18:01:10.131343] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:01:10.131357] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34015,-122.22369 (batch tracking: 1 repeaters, rxCount: 6) +[2026-02-20T18:01:10.131370] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) +[2026-02-20T18:01:10.131397] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.34015,-122.22369 +[2026-02-20T18:01:11.518346] LOG: [CONN] Frame received (91 bytes): 88 32 c8 15 29 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab +[2026-02-20T18:01:11.518363] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:11.518372] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:11.518387] LOG: [RX PARSE] RAW Packet (88 bytes): 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:11.518390] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:11.518392] LOG: [RX PARSE] Path length offset: 1, Path length: 41 +[2026-02-20T18:01:11.518397] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=41, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=45 bytes +[2026-02-20T18:01:11.518400] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=41 +[2026-02-20T18:01:11.518401] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:11.518403] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 +[2026-02-20T18:01:11.518405] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:11.518407] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd +[2026-02-20T18:01:11.518409] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:11.518412] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:01:11.518413] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:01:11.518415] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:01:11.518418] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:11.518464] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:11.518470] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:11.518571] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:11.518575] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:11.518578] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:01:11.518602] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:11.518606] LOG: [RX FILTER] Raw packet (88 bytes): 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:11.518612] LOG: [RX FILTER] Header: 0x15 | PathLength: 41 | SNR: 12.5 +[2026-02-20T18:01:11.518614] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:11.518617] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:11.518621] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:11.518625] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:11.518627] LOG: [RX FILTER] Encrypted message: 42 bytes +[2026-02-20T18:01:11.518632] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:11.518668] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:11.518681] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:11.518767] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) + + +[2026-02-20T18:01:11.518795] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:11.518798] LOG: [RX LOG] Dropped packet hex: 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB +[2026-02-20T18:01:11.702655] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:01:12.602831] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:12.794405] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 08 00 00 00 6e 23 00 00 +[2026-02-20T18:01:12.794573] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:12.794593] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:13.109698] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:01:14.882773] LOG: [PING] RX listening window ended +[2026-02-20T18:01:14.882887] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:01:14.882910] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:01:14.882966] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:01:14.882979] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:01:14.882989] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:01:14.883006] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:01:14.883022] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:01:14.883400] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:01:17.604] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:17.656099] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 08 00 00 00 6e 23 00 00 +[2026-02-20T18:01:17.656210] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:17.656228] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:17.898544] LOG: [CONN] Frame received (129 bytes): 88 27 98 15 09 bf 1c 0a 1b ab 5a 7a 7e dd ef 42 dd f2 2a 93 9a 4d 81 3e b1 54 5d cf 1e 94 49 f5 65 26 e4 58 5c 3d 13 b1 70 a9 f4 81 24 b1 86 76 b8 79 78 86 2f a1 21 fa 20 ea 2a ee 14 37 66 c9 31 cb 33 b9 cf 85 9a 21 84 97 c6 f9 c2 80 5f fa df 6b de aa ee 18 df 39 30 09 92 11 9d 17 ff ce f9 c8 03 7d 0e 9c 72 ea fc c7 ac 79 2c 2b 65 b0 67 90 a4 90 7a 9f 69 48 fa c0 a9 7f 5b f3 03 ff 05 +[2026-02-20T18:01:17.898656] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:17.898683] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:17.898733] LOG: [RX PARSE] RAW Packet (126 bytes): 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 +[2026-02-20T18:01:17.898742] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:17.898752] LOG: [RX PARSE] Path length offset: 1, Path length: 9 +[2026-02-20T18:01:17.898766] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0xbf, lastHop=0xdd, SNR=9.75, RSSI=-104, payload=115 bytes +[2026-02-20T18:01:17.898774] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 +[2026-02-20T18:01:17.898779] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:17.898783] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:17.898827] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:17.898835] LOG: [RX FILTER] Raw packet (126 bytes): 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 +[2026-02-20T18:01:17.898846] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 9.75 +[2026-02-20T18:01:17.898853] LOG: [RX FILTER] ✓ RSSI OK (-104 < -30) +[2026-02-20T18:01:17.898857] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:17.898884] LOG: [RX FILTER] Channel hash: 0xef +[2026-02-20T18:01:17.898890] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xef +[2026-02-20T18:01:17.898939] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:01:17.898947] LOG: [RX LOG] Dropped packet hex: 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 +[2026-02-20T18:01:18.014656] LOG: [GPS SERVICE] Position stream fired: lat=47.34017, lon=-122.22260, accuracy=3.8m +[2026-02-20T18:01:18.014724] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:01:18.014734] LOG: [RX BATCH] Distance check for repeater CC: 82.23m from first observation (threshold=25m) +[2026-02-20T18:01:18.014741] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:01:18.014744] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:01:18.014751] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:01:18.014756] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.34015,-122.22369 +[2026-02-20T18:01:18.014760] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:01:18.014766] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.34015,-122.22369 +[2026-02-20T18:01:18.014771] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:01:18.014778] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:01:18.014783] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=15 +[2026-02-20T18:01:18.014799] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:01:18.014803] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:01:19.885371] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:01:19.885618] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:01:19.885639] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:01:19.885652] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:01:19.886837] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue +[2026-02-20T18:01:20.383765] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:01:20.383817] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:01:20.383829] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771639580} +[2026-02-20T18:01:20.383841] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:01:20.383852] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:01:20.384524] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:01:20.384541] LOG: [APP] Upload success: +2 items (total: 8) +[2026-02-20T18:01:22.573756] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:01:22.573855] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:01:22.573876] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:01:22.605348] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:22.784777] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 98 27 08 00 00 00 6f 23 00 00 +[2026-02-20T18:01:22.784902] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:22.784926] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:01:22.831413] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:01:22.831490] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:01:22.831506] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771639582} +[2026-02-20T18:01:22.831564] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:01:22.831599] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:01:22.831978] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:01:22.831994] LOG: [APP] Upload success: +1 items (total: 9) +[2026-02-20T18:01:26.791819] LOG: [CONN] Frame received (107 bytes): 88 31 9e 15 39 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e 5a 2d ab a4 61 c1 43 1c 89 0a 1b ab 5a a7 cf 7a 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a a8 +[2026-02-20T18:01:26.791880] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:26.791924] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:26.792024] LOG: [RX PARSE] RAW Packet (104 bytes): 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:26.792049] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:26.792062] LOG: [RX PARSE] Path length offset: 1, Path length: 57 +[2026-02-20T18:01:26.792096] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=57, firstHop=0xcc, lastHop=0xdd, SNR=12.25, RSSI=-98, payload=45 bytes +[2026-02-20T18:01:26.792113] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=57 +[2026-02-20T18:01:26.792123] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:26.792139] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:26.792151] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:01:26.792238] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:26.792250] LOG: [RX FILTER] Raw packet (104 bytes): 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:26.792274] LOG: [RX FILTER] Header: 0x15 | PathLength: 57 | SNR: 12.25 +[2026-02-20T18:01:26.792284] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:26.792298] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:26.792310] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:26.792322] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:26.792338] LOG: [RX FILTER] Encrypted message: 42 bytes +[2026-02-20T18:01:26.792351] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:26.792516] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:26.792666] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:26.792906] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:26.793033] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:26.793051] LOG: [RX LOG] Dropped packet hex: 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:27.300453] LOG: [CONN] Frame received (108 bytes): 88 31 c5 15 3a cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e 5a 2d ab a4 61 c1 43 1c 89 0a 1b ab 5a a7 cf 7a 7e 9b cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a a8 +[2026-02-20T18:01:27.300582] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:27.300610] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:27.300680] LOG: [RX PARSE] RAW Packet (105 bytes): 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:27.300698] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:27.300707] LOG: [RX PARSE] Path length offset: 1, Path length: 58 +[2026-02-20T18:01:27.300729] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=58, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=45 bytes +[2026-02-20T18:01:27.300741] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=58 +[2026-02-20T18:01:27.300752] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:27.300762] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:27.300772] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD +[2026-02-20T18:01:27.300846] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:27.300856] LOG: [RX FILTER] Raw packet (105 bytes): 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:27.300875] LOG: [RX FILTER] Header: 0x15 | PathLength: 58 | SNR: 12.25 +[2026-02-20T18:01:27.300882] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:01:27.300895] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:27.300904] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:27.300914] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:27.300927] LOG: [RX FILTER] Encrypted message: 42 bytes +[2026-02-20T18:01:27.300936] LOG: [CRYPTO] Decrypting message (42 bytes) +[2026-02-20T18:01:27.301073] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:27.301112] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:27.301405] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:27.301516] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:27.301529] LOG: [RX LOG] Dropped packet hex: 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 +[2026-02-20T18:01:27.602898] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:01:27.603132] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:27.641986] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:01:27.642102] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:01:27.642125] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:01:27.642142] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:01:27.707990] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c5 31 08 00 00 00 70 23 00 00 +[2026-02-20T18:01:27.708111] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:27.708130] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:01:27.832713] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:01:32.603135] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:32.780026] LOG: [CONN] Frame received (91 bytes): 88 2d 9e 15 03 c7 7e dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f 80 80 49 +[2026-02-20T18:01:32.780232] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:32.780303] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:32.780433] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 C7 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 +[2026-02-20T18:01:32.780462] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:32.780474] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:01:32.780522] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xc7, lastHop=0xdd, SNR=11.25, RSSI=-98, payload=83 bytes +[2026-02-20T18:01:32.780548] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:01:32.780559] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:32.780574] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:32.780651] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:32.780663] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 C7 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 +[2026-02-20T18:01:32.780686] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 +[2026-02-20T18:01:32.780700] LOG: [RX FILTER] ✓ RSSI OK (-98 < -30) +[2026-02-20T18:01:32.780716] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:32.780727] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:32.780738] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:32.780755] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:01:32.780765] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:01:32.780866] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:01:32.781020] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40731, -122.50463 [..." +[2026-02-20T18:01:32.781050] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:01:32.781060] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:01:32.781090] LOG: [RX LOG] Packet heard via last hop: DD, SNR=11.25, path_length=3 +[2026-02-20T18:01:32.781107] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:01:32.781123] LOG: [RX BATCH] First observation for repeater DD: SNR=11.25 +[2026-02-20T18:01:32.781139] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:01:32.781162] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:01:32.781182] LOG: [APP] Immediate RX observation: repeater=DD, snr=11.25, location=47.34017,-122.22260 +[2026-02-20T18:01:32.781213] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:01:32.781233] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34017,-122.22260 (batch tracking: 1 repeaters, rxCount: 7) +[2026-02-20T18:01:32.781257] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) +[2026-02-20T18:01:32.781276] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=11.25, location=47.34017,-122.22260 +[2026-02-20T18:01:32.781744] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:01:32.781758] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:01:32.781768] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:01:32.802932] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 9e 2d 08 00 00 00 70 23 00 00 +[2026-02-20T18:01:32.802967] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:32.802976] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:34.084218] LOG: [CONN] Frame received (92 bytes): 88 30 c4 15 04 c7 7e 2a cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f 80 80 49 +[2026-02-20T18:01:34.084364] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:34.084393] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:34.084487] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 C7 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 +[2026-02-20T18:01:34.084505] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:34.084521] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:01:34.084579] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=83 bytes +[2026-02-20T18:01:34.084598] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:01:34.084611] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:34.084621] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:34.084702] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:34.084715] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 C7 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 +[2026-02-20T18:01:34.084739] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 +[2026-02-20T18:01:34.084754] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:01:34.084769] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:34.084783] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:34.084794] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:34.084811] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:01:34.084824] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:01:34.084923] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:01:34.085104] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40731, -122.50463 [..." +[2026-02-20T18:01:34.085133] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:01:34.085143] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:01:34.085173] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 +[2026-02-20T18:01:34.085184] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:01:34.085206] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 +[2026-02-20T18:01:34.085223] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:01:34.085246] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:01:34.085269] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.34017,-122.22260 +[2026-02-20T18:01:34.085306] LOG: [APP] Current batch tracking: 1 repeaters: {DD} +[2026-02-20T18:01:34.085326] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34017,-122.22260 (batch tracking: 2 repeaters, rxCount: 8) +[2026-02-20T18:01:34.085351] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:01:34.085372] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.34017,-122.22260 +[2026-02-20T18:01:37.574051] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:01:37.574147] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:01:37.602906] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:37.723152] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 08 00 00 00 70 23 00 00 +[2026-02-20T18:01:37.723299] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:37.723325] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:40.018568] LOG: [GPS SERVICE] Position stream fired: lat=47.34022, lon=-122.22241, accuracy=3.8m +[2026-02-20T18:01:40.018636] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:01:40.018652] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger +[2026-02-20T18:01:40.018666] LOG: [RX BATCH] Distance check for repeater DD: 14.97m from first observation (threshold=25m) +[2026-02-20T18:01:40.018669] LOG: [RX BATCH] Distance check for repeater CC: 14.97m from first observation (threshold=25m) +[2026-02-20T18:01:40.018687] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:01:42.358301] LOG: [CONN] Frame received (96 bytes): 88 2b 9c 15 0b c7 7e 75 20 20 20 53 7a 7e 2a dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f +[2026-02-20T18:01:42.358318] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:42.358330] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:42.358348] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.358353] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:42.358355] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:01:42.358364] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xdd, SNR=10.75, RSSI=-100, payload=80 bytes +[2026-02-20T18:01:42.358367] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:01:42.358369] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:42.358372] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:42.358388] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:42.358390] LOG: [RX FILTER] Raw packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.358394] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 10.75 +[2026-02-20T18:01:42.358399] LOG: [RX FILTER] ✓ RSSI OK (-100 < -30) +[2026-02-20T18:01:42.358413] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:42.358427] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:42.358446] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:42.358448] LOG: [RX FILTER] Encrypted message: 77 bytes +[2026-02-20T18:01:42.358450] LOG: [CRYPTO] Decrypting message (77 bytes) +[2026-02-20T18:01:42.358506] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:42.358598] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:42.358662] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:42.358689] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:42.358691] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.602599] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:42.616969] LOG: [CONN] Frame received (96 bytes): 88 30 c5 15 0b c7 7e 75 20 20 20 53 7a 7e 2a cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f +[2026-02-20T18:01:42.616999] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:42.617007] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:42.617023] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.617028] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:42.617031] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:01:42.617037] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=80 bytes +[2026-02-20T18:01:42.617041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:01:42.617044] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:42.617046] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:42.617060] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:42.617063] LOG: [RX FILTER] Raw packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.617068] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.0 +[2026-02-20T18:01:42.617070] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:01:42.617073] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:42.617081] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:42.617084] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:42.617089] LOG: [RX FILTER] Encrypted message: 77 bytes +[2026-02-20T18:01:42.617091] LOG: [CRYPTO] Decrypting message (77 bytes) +[2026-02-20T18:01:42.617164] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:42.617178] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:42.617223] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:42.617250] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:42.617253] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F +[2026-02-20T18:01:42.643955] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c5 30 08 00 00 00 71 23 00 00 +[2026-02-20T18:01:42.643994] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:42.644001] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:01:43.378237] LOG: [CONN] Frame received (94 bytes): 88 1a 93 15 0a c7 7e 75 20 20 20 20 53 7e dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd +[2026-02-20T18:01:43.378296] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:43.378306] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:43.378325] LOG: [RX PARSE] RAW Packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:43.378329] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:43.378333] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:01:43.378345] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xc7, lastHop=0xdd, SNR=6.5, RSSI=-109, payload=79 bytes +[2026-02-20T18:01:43.378349] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:01:43.378353] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:43.378355] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:43.378371] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:43.378375] LOG: [RX FILTER] Raw packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:43.378381] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 6.5 +[2026-02-20T18:01:43.378385] LOG: [RX FILTER] ✓ RSSI OK (-109 < -30) +[2026-02-20T18:01:43.378387] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:43.378392] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:43.378394] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:43.378396] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:01:43.378402] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:01:43.378496] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:43.378512] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:43.378577] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:43.378604] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:43.378608] LOG: [RX LOG] Dropped packet hex: 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:43.798062] LOG: [CONN] Frame received (94 bytes): 88 2f c6 15 0a c7 7e 75 20 20 20 20 53 7e cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd +[2026-02-20T18:01:43.798111] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:43.798120] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:43.798135] LOG: [RX PARSE] RAW Packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:43.798140] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:43.798143] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:01:43.798153] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xc7, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=79 bytes +[2026-02-20T18:01:43.798156] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:01:43.798158] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:43.798160] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:43.798175] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:43.798179] LOG: [RX FILTER] Raw packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:43.798184] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 11.75 +[2026-02-20T18:01:43.798189] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:01:43.798191] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:43.798194] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:01:43.798197] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:01:43.798200] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:01:43.798204] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:01:43.798264] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:43.798308] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:01:43.798363] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:01:43.798387] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:01:43.798393] LOG: [RX LOG] Dropped packet hex: 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD +[2026-02-20T18:01:44.884641] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:01:44.884791] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:01:44.884809] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:01:44.884857] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:01:44.884898] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34022, -122.22241 [0.3w]" +[2026-02-20T18:01:44.884915] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:01:44.884925] LOG: [TX LOG] Payload: "@[MapperBot] 47.34022, -122.22241 [0.3w]" +[2026-02-20T18:01:44.884938] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:01:44.884955] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:01:44.884968] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:01:44.884979] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:01:44.885005] LOG: [CONN] Sending ping: @[MapperBot] 47.34022, -122.22241 [0.3w] +[2026-02-20T18:01:45.011657] LOG: [GPS SERVICE] Position stream fired: lat=47.34061, lon=-122.22225, accuracy=3.8m +[2026-02-20T18:01:45.011744] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger +[2026-02-20T18:01:45.011755] LOG: [RX BATCH] Distance check for repeater DD: 55.21m from first observation (threshold=25m) +[2026-02-20T18:01:45.011759] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:01:45.011762] LOG: [RX BATCH] Distance check for repeater CC: 55.21m from first observation (threshold=25m) +[2026-02-20T18:01:45.011767] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:01:45.011769] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:01:45.011775] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:01:45.011782] LOG: [RX BATCH] Posting repeater DD: snr=11.25, location=47.34017,-122.22260 +[2026-02-20T18:01:45.011785] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:01:45.011790] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=11.25, location=47.34017,-122.22260 +[2026-02-20T18:01:45.011796] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 11.25 <= pin 11.25 +[2026-02-20T18:01:45.011802] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 +[2026-02-20T18:01:45.011807] LOG: [APP] Added RX log entry: repeater=DD, snr=11.25, pathLen=3 +[2026-02-20T18:01:45.011824] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:01:45.011826] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:01:45.011830] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:01:45.011834] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.34017,-122.22260 +[2026-02-20T18:01:45.011837] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:01:45.011841] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.34017,-122.22260 +[2026-02-20T18:01:45.011843] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 +[2026-02-20T18:01:45.011849] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:01:45.011852] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 +[2026-02-20T18:01:45.011858] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:01:45.011862] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement +[2026-02-20T18:01:45.040969] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:01:45.041009] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:01:45.041013] LOG: [CONN] Received OK response +[2026-02-20T18:01:46.680654] LOG: [CONN] Frame received (73 bytes): 88 12 8f 15 01 dd 81 e4 86 22 30 90 70 77 65 f7 af ee 40 53 b3 bc 00 a1 fd 5d b1 eb 1e 09 f1 fc cf d6 92 69 64 ae ea 10 45 8a 8e 97 ca be a2 72 bd ca f7 03 b0 66 b4 f7 dc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:01:46.680685] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:46.680705] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:46.680733] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 DD 81 E4 86 22 30 90 70 77 65 F7 AF EE 40 53 B3 BC 00 A1 FD 5D B1 EB 1E 09 F1 FC CF D6 92 69 64 AE EA 10 45 8A 8E 97 CA BE A2 72 BD CA F7 03 B0 66 B4 F7 DC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:01:46.680739] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:46.680745] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:01:46.680760] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xdd, lastHop=0xdd, SNR=4.5, RSSI=-113, payload=67 bytes +[2026-02-20T18:01:46.680768] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:01:46.680774] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:46.680778] LOG: [TX LOG] Processing rx_log entry: SNR=4.5, RSSI=-113 +[2026-02-20T18:01:46.680784] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:46.680791] LOG: [TX LOG] ✓ RSSI OK (-113 < -30) +[2026-02-20T18:01:46.680796] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:01:46.680805] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:01:46.680809] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:01:46.680815] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:01:46.680855] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:01:46.680944] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... +[2026-02-20T18:01:46.680954] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.34022, -122.22241 [0.3w]" (47 chars) +[2026-02-20T18:01:46.680959] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.34022, -122.22241 [0.3w]" (40 chars) +[2026-02-20T18:01:46.680965] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! +[2026-02-20T18:01:46.680972] LOG: [PING] Repeater echo accepted: first_hop=dd, SNR=4.5, full_path_length=1 +[2026-02-20T18:01:46.680979] LOG: [PING] Adding new repeater echo: path=dd, SNR=4.5, RSSI=-113 +[2026-02-20T18:01:46.680986] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) +[2026-02-20T18:01:46.680991] LOG: [PING] onEchoReceived callback fired: dd, SNR=4.5, RSSI=-113, isNew=true +[2026-02-20T18:01:46.680999] LOG: [PING] Real-time: Added new repeater dd (SNR: 4.5) - total: 1 +[2026-02-20T18:01:46.681003] LOG: [PING] Calling onEchoReceived callback (callback=SET) +[2026-02-20T18:01:46.681008] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== +[2026-02-20T18:01:46.681015] LOG: [APP] Real-time echo: dd (SNR: 4.5, isNew: true) +[2026-02-20T18:01:46.681020] LOG: [APP] TxLogEntries count: 4 +[2026-02-20T18:01:46.681027] LOG: [APP] Updated TxLogEntry with 1 events (real-time) +[2026-02-20T18:01:46.681031] LOG: [APP] Calling notifyListeners() to update UI +[2026-02-20T18:01:46.681037] LOG: [APP] notifyListeners() completed +[2026-02-20T18:01:46.681043] LOG: [PING] onEchoReceived callback completed +[2026-02-20T18:01:46.681048] LOG: [TX LOG] onEchoReceived callback invoked successfully +[2026-02-20T18:01:46.681052] LOG: [TX LOG] ✅ Echo tracked successfully +[2026-02-20T18:01:46.681110] LOG: [UNIFIED RX] Packet was TX echo, done +[2026-02-20T18:01:47.460560] LOG: [CONN] Frame received (73 bytes): 88 32 c6 15 01 cc 81 e4 86 22 30 90 70 77 65 f7 af ee 40 53 b3 bc 00 a1 fd 5d b1 eb 1e 09 f1 fc cf d6 92 69 64 ae ea 10 45 8a 8e 97 ca be a2 72 bd ca f7 03 b0 66 b4 f7 dc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:01:47.460728] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:47.460759] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:47.460833] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 E4 86 22 30 90 70 77 65 F7 AF EE 40 53 B3 BC 00 A1 FD 5D B1 EB 1E 09 F1 FC CF D6 92 69 64 AE EA 10 45 8A 8E 97 CA BE A2 72 BD CA F7 03 B0 66 B4 F7 DC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:01:47.460854] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:47.460864] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:01:47.460899] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes +[2026-02-20T18:01:47.460913] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:01:47.460927] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:01:47.460941] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 +[2026-02-20T18:01:47.460951] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:01:47.460965] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:01:47.460978] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:47.460987] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:47.461002] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:01:47.605992] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:47.656450] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 32 08 00 00 00 72 23 00 00 +[2026-02-20T18:01:47.656581] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:47.656607] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:01:48.042157] LOG: [PING] Ping sent successfully +[2026-02-20T18:01:49.886384] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) +[2026-02-20T18:01:49.886710] LOG: [TX LOG] Final: dd -> SNR=4.5, seen=1x +[2026-02-20T18:01:50.450298] LOG: [GPS SERVICE] Position stream fired: lat=47.34125, lon=-122.22220, accuracy=3.8m +[2026-02-20T18:01:52.573651] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:01:52.573749] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:01:52.573757] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:01:52.574910] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue +[2026-02-20T18:01:52.602651] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:52.692253] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 32 08 00 00 00 72 23 00 00 +[2026-02-20T18:01:52.692331] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:52.692342] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:01:53.042914] LOG: [PING] RX listening window ended +[2026-02-20T18:01:53.043037] LOG: [PING] TxTracker collected 1 repeater echoes +[2026-02-20T18:01:53.043068] LOG: [PING] Heard repeater: dd, SNR=4.5 +[2026-02-20T18:01:53.043317] LOG: [GRAPH] Recorded txSuccess event at -119dBm with 1 repeater(s) +[2026-02-20T18:01:53.043377] LOG: [PING] Queued TX entry with heard_repeats: dd(4.50) +[2026-02-20T18:01:53.043388] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:01:53.043402] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:01:53.043449] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:01:53.043466] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:01:53.044205] LOG: [API QUEUE] TX enqueued: dd(4.50) (queue size: 3) +[2026-02-20T18:01:53.260980] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:01:53.261015] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:01:53.261023] LOG: [API] Response (200) in 0.69s: {"success":true,"expires_at":1771639613} +[2026-02-20T18:01:53.261030] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:01:53.261038] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:01:53.261239] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:01:53.261249] LOG: [APP] Upload success: +1 items (total: 10) +[2026-02-20T18:01:55.470302] LOG: [GPS SERVICE] Position stream fired: lat=47.34201, lon=-122.22225, accuracy=3.8m +[2026-02-20T18:01:57.437946] LOG: [CONN] Frame received (76 bytes): 88 0a 8e 15 04 15 ae 7e dd 11 89 be e5 da cc cb dd 57 18 90 85 61 6f 39 2c 8e ab 03 b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 +[2026-02-20T18:01:57.437994] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:01:57.438028] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:01:57.438074] LOG: [RX PARSE] RAW Packet (73 bytes): 15 04 15 AE 7E DD 11 89 BE E5 DA CC CB DD 57 18 90 85 61 6F 39 2C 8E AB 03 B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:57.438085] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:01:57.438096] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:01:57.438121] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xdd, SNR=2.5, RSSI=-114, payload=67 bytes +[2026-02-20T18:01:57.438134] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:01:57.438142] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:01:57.438148] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:01:57.438190] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:01:57.438200] LOG: [RX FILTER] Raw packet (73 bytes): 15 04 15 AE 7E DD 11 89 BE E5 DA CC CB DD 57 18 90 85 61 6F 39 2C 8E AB 03 B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 +[2026-02-20T18:01:57.438212] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 2.5 +[2026-02-20T18:01:57.438226] LOG: [RX FILTER] ✓ RSSI OK (-114 < -30) +[2026-02-20T18:01:57.438233] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:01:57.438239] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:01:57.438254] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:01:57.438261] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:01:57.438268] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:01:57.438333] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:01:57.438487] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" +[2026-02-20T18:01:57.438503] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:01:57.438509] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:01:57.438739] LOG: [RX LOG] Packet heard via last hop: DD, SNR=2.5, path_length=4 +[2026-02-20T18:01:57.438751] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:01:57.438763] LOG: [RX BATCH] First observation for repeater DD: SNR=2.5 +[2026-02-20T18:01:57.438779] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:01:57.438798] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:01:57.438815] LOG: [APP] Immediate RX observation: repeater=DD, snr=2.5, location=47.34201,-122.22225 +[2026-02-20T18:01:57.438828] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:01:57.438844] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34201,-122.22225 (batch tracking: 1 repeaters, rxCount: 9) +[2026-02-20T18:01:57.438863] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:01:57.438876] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=2.5, location=47.34201,-122.22225 +[2026-02-20T18:01:57.439157] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:01:57.439164] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:01:57.439218] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:01:57.602852] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:01:57.603072] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:01:57.645001] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:01:57.645129] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:01:57.645146] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:01:57.645162] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:01:57.703483] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 8e 0a 08 00 00 00 72 23 00 00 +[2026-02-20T18:01:57.703567] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:01:57.703582] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:01:58.044640] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:01:58.044848] LOG: [API QUEUE] Item 1/2: type=RX, external_antenna=true +[2026-02-20T18:01:58.044865] LOG: [API QUEUE] Item 2/2: type=TX, external_antenna=true +[2026-02-20T18:01:58.044881] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:01:58.261657] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:01:58.298735] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:01:58.298763] LOG: [API] Request: {"data":"2 items","items":"RX:external_antenna=true, TX:external_antenna=true"} +[2026-02-20T18:01:58.298767] LOG: [API] Response (200) in 0.25s: {"success":true,"expires_at":1771639618} +[2026-02-20T18:01:58.298773] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:01:58.298778] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:01:58.298990] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:01:58.298997] LOG: [APP] Upload success: +2 items (total: 12) +[2026-02-20T18:02:00.457498] LOG: [GPS SERVICE] Position stream fired: lat=47.34271, lon=-122.22227, accuracy=3.8m +[2026-02-20T18:02:00.457605] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:02:00.457618] LOG: [RX BATCH] Distance check for repeater DD: 78.62m from first observation (threshold=25m) +[2026-02-20T18:02:00.457622] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:02:00.457629] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:02:00.457636] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:02:00.457643] LOG: [RX BATCH] Posting repeater DD: snr=2.5, location=47.34201,-122.22225 +[2026-02-20T18:02:00.457650] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:02:00.457653] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=2.5, location=47.34201,-122.22225 +[2026-02-20T18:02:00.457661] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 2.50 <= pin 2.50 +[2026-02-20T18:02:00.457667] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 +[2026-02-20T18:02:00.457673] LOG: [APP] Added RX log entry: repeater=DD, snr=2.5, pathLen=4 +[2026-02-20T18:02:00.457693] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:02:00.457696] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:02:02.603858] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:02.774963] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 8e 0a 08 00 00 00 72 23 00 00 +[2026-02-20T18:02:02.775106] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:02.775122] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:03.303085] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:02:03.903497] LOG: [CONN] Frame received (83 bytes): 88 f6 87 15 0b 7b bc e3 28 aa cd be 7a 53 7e dd 81 ba 57 da d0 15 24 78 65 fd 25 aa 70 a7 bd fd 40 8a ff 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 68 80 74 57 ac a4 12 da e9 3c 30 7e c0 9c 59 0e 88 bc f2 33 99 03 2a 71 35 6d 3f 6a e6 e1 2a 40 +[2026-02-20T18:02:03.903639] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:03.903668] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:03.903746] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 7B BC E3 28 AA CD BE 7A 53 7E DD 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 +[2026-02-20T18:02:03.903769] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:02:03.903785] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:02:03.903813] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x7b, lastHop=0xdd, SNR=-2.5, RSSI=-121, payload=67 bytes +[2026-02-20T18:02:03.903831] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:02:03.903843] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:03.903853] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:03.903932] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:03.903949] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 7B BC E3 28 AA CD BE 7A 53 7E DD 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 +[2026-02-20T18:02:03.903972] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: -2.5 +[2026-02-20T18:02:03.903988] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) +[2026-02-20T18:02:03.903999] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:02:03.904014] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:02:03.904028] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:02:03.904040] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:02:03.904056] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:02:03.904142] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:02:03.904294] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.92800, -123.75212 [0.3w]" +[2026-02-20T18:02:03.904317] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:02:03.904333] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:02:03.904361] LOG: [RX LOG] Packet heard via last hop: DD, SNR=-2.5, path_length=11 +[2026-02-20T18:02:03.904373] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:02:03.904389] LOG: [RX BATCH] First observation for repeater DD: SNR=-2.5 +[2026-02-20T18:02:03.904410] LOG: [RX BATCH] Started 30s timeout timer for repeater DD +[2026-02-20T18:02:03.904427] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) +[2026-02-20T18:02:03.904452] LOG: [APP] Immediate RX observation: repeater=DD, snr=-2.5, location=47.34271,-122.22227 +[2026-02-20T18:02:03.904470] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:02:03.904530] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34271,-122.22227 (batch tracking: 1 repeaters, rxCount: 10) +[2026-02-20T18:02:03.904551] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:02:03.904576] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=-2.5, location=47.34271,-122.22227 +[2026-02-20T18:02:03.905035] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:02:03.905053] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:02:03.905067] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:02:05.016505] LOG: [GPS SERVICE] Position stream fired: lat=47.34345, lon=-122.22221, accuracy=3.8m +[2026-02-20T18:02:05.016582] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:02:05.016590] LOG: [RX BATCH] Distance check for repeater DD: 82.07m from first observation (threshold=25m) +[2026-02-20T18:02:05.016595] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush +[2026-02-20T18:02:05.016599] LOG: [RX BATCH] Flushing repeater DD +[2026-02-20T18:02:05.016603] LOG: [RX BATCH] Cleared timeout timer for repeater DD +[2026-02-20T18:02:05.016610] LOG: [RX BATCH] Posting repeater DD: snr=-2.5, location=47.34271,-122.22227 +[2026-02-20T18:02:05.016613] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:02:05.016617] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=-2.5, location=47.34271,-122.22227 +[2026-02-20T18:02:05.016624] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best -2.50 <= pin -2.50 +[2026-02-20T18:02:05.016629] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 +[2026-02-20T18:02:05.016634] LOG: [APP] Added RX log entry: repeater=DD, snr=-2.5, pathLen=11 +[2026-02-20T18:02:05.016648] LOG: [RX BATCH] Repeater DD removed from buffer +[2026-02-20T18:02:05.016651] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:02:05.810794] LOG: [CONN] Frame received (84 bytes): 88 31 c6 15 0c 7b bc e3 28 aa cd be 7a 53 7e dd cc 81 ba 57 da d0 15 24 78 65 fd 25 aa 70 a7 bd fd 40 8a ff 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 68 80 74 57 ac a4 12 da e9 3c 30 7e c0 9c 59 0e 88 bc f2 33 99 03 2a 71 35 6d 3f 6a e6 e1 2a 40 +[2026-02-20T18:02:05.810931] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:05.810960] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:05.811037] LOG: [RX PARSE] RAW Packet (81 bytes): 15 0C 7B BC E3 28 AA CD BE 7A 53 7E DD CC 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 +[2026-02-20T18:02:05.811061] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:02:05.811072] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:02:05.811105] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x7b, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=67 bytes +[2026-02-20T18:02:05.811119] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:02:05.811134] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:05.811144] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:05.811225] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:05.811241] LOG: [RX FILTER] Raw packet (81 bytes): 15 0C 7B BC E3 28 AA CD BE 7A 53 7E DD CC 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 +[2026-02-20T18:02:05.811260] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 +[2026-02-20T18:02:05.811279] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:02:05.811291] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:02:05.811301] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:02:05.811318] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:02:05.811332] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:02:05.811347] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:02:05.811432] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:02:05.811579] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.92800, -123.75212 [0.3w]" +[2026-02-20T18:02:05.811601] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:02:05.811616] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:02:05.811642] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=12 +[2026-02-20T18:02:05.811658] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:02:05.811673] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:02:05.811695] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:02:05.811714] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:02:05.811738] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.34345,-122.22221 +[2026-02-20T18:02:05.811756] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:02:05.811779] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34345,-122.22221 (batch tracking: 1 repeaters, rxCount: 11) +[2026-02-20T18:02:05.811798] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:02:05.811843] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.34345,-122.22221 +[2026-02-20T18:02:07.573842] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:02:07.573973] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:02:07.573984] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:02:07.575958] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue +[2026-02-20T18:02:07.606932] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:07.665120] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 08 00 00 00 73 23 00 00 +[2026-02-20T18:02:07.665240] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:07.665265] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:07.893234] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:02:07.893293] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:02:07.893311] LOG: [API] Response (200) in 0.32s: {"success":true,"expires_at":1771639627} +[2026-02-20T18:02:07.893324] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:02:07.893348] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:02:07.896190] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:02:07.896214] LOG: [APP] Upload success: +1 items (total: 13) +[2026-02-20T18:02:08.352601] LOG: [CONN] Frame received (33 bytes): 88 31 c7 01 08 d7 99 ab 50 6c c7 29 cc 68 06 d4 36 45 10 bc c3 bd 11 9f de b9 06 74 7f f2 43 9c 6b +[2026-02-20T18:02:08.352680] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:08.352698] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:08.352717] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B +[2026-02-20T18:02:08.352722] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:02:08.352728] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:02:08.352738] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xd7, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=20 bytes +[2026-02-20T18:02:08.352747] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 +[2026-02-20T18:02:08.352751] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:08.352760] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:08.352776] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:08.352781] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B +[2026-02-20T18:02:08.352788] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 12.25 +[2026-02-20T18:02:08.352796] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:02:08.352800] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:02:08.352820] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:02:08.352826] LOG: [RX LOG] Dropped packet hex: 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B +[2026-02-20T18:02:10.666643] LOG: [CONN] Frame received (38 bytes): 88 30 c7 01 0f d7 99 ab 50 6c 24 38 75 20 20 20 75 e3 7e cc 68 06 d4 36 45 10 bc c3 bd 11 9f de b9 06 74 7f f2 43 +[2026-02-20T18:02:10.666768] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:10.666785] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:10.666805] LOG: [RX PARSE] RAW Packet (35 bytes): 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 +[2026-02-20T18:02:10.666813] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:02:10.666818] LOG: [RX PARSE] Path length offset: 1, Path length: 15 +[2026-02-20T18:02:10.666837] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=15, firstHop=0xd7, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=18 bytes +[2026-02-20T18:02:10.666843] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=15 +[2026-02-20T18:02:10.666850] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:10.666856] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:10.666874] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:10.666879] LOG: [RX FILTER] Raw packet (35 bytes): 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 +[2026-02-20T18:02:10.666888] LOG: [RX FILTER] Header: 0x01 | PathLength: 15 | SNR: 12.0 +[2026-02-20T18:02:10.666894] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:02:10.666902] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:02:10.666928] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:02:10.666933] LOG: [RX LOG] Dropped packet hex: 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 +[2026-02-20T18:02:11.011254] LOG: [GPS SERVICE] Position stream fired: lat=47.34435, lon=-122.22221, accuracy=3.8m +[2026-02-20T18:02:11.011326] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:02:11.011372] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:02:11.011381] LOG: [RX BATCH] Distance check for repeater CC: 99.54m from first observation (threshold=25m) +[2026-02-20T18:02:11.011384] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:02:11.011392] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:02:11.011396] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:02:11.011402] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.34345,-122.22221 +[2026-02-20T18:02:11.011406] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:02:11.011409] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.34345,-122.22221 +[2026-02-20T18:02:11.011416] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:02:11.011421] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:02:11.011425] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=12 +[2026-02-20T18:02:11.011439] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:02:11.011454] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:02:11.011457] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:02:12.602972] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:12.675407] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 +[2026-02-20T18:02:12.675551] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:12.675572] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:12.906429] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:02:17.602686] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:17.650387] LOG: [GPS SERVICE] Position stream fired: lat=47.34528, lon=-122.22221, accuracy=3.8m +[2026-02-20T18:02:17.686701] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 +[2026-02-20T18:02:17.686823] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:17.686838] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:22.573683] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:02:22.573769] LOG: [API QUEUE] Item 1/2: type=RX, external_antenna=true +[2026-02-20T18:02:22.573776] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:02:22.573780] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:02:22.574485] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:02:22.602583] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:22.691552] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 +[2026-02-20T18:02:22.691641] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:22.691650] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:23.044104] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:02:23.044235] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:02:23.044260] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:02:23.044302] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:02:23.044347] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34528, -122.22221 [0.3w]" +[2026-02-20T18:02:23.044360] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:02:23.044369] LOG: [TX LOG] Payload: "@[MapperBot] 47.34528, -122.22221 [0.3w]" +[2026-02-20T18:02:23.044388] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:02:23.044402] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:02:23.044417] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:02:23.044430] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:02:23.044451] LOG: [CONN] Sending ping: @[MapperBot] 47.34528, -122.22221 [0.3w] +[2026-02-20T18:02:23.095376] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:02:23.095445] LOG: [API] Request: {"data":"2 items","items":"RX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:02:23.095459] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771639642} +[2026-02-20T18:02:23.095473] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:02:23.095491] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:02:23.095995] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:02:23.096002] LOG: [APP] Upload success: +2 items (total: 15) +[2026-02-20T18:02:23.204903] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:02:23.205030] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:02:23.205050] LOG: [CONN] Received OK response +[2026-02-20T18:02:24.063627] LOG: [CONN] Frame received (73 bytes): 88 30 c6 15 01 cc 81 c4 68 71 36 d7 8f 0f f6 f4 df 4e 50 e6 c6 35 04 0d 83 f5 30 ea b1 a3 ee eb fc 98 03 5f 82 73 0f c8 88 34 2b 27 ec 76 f1 cc bd 5b 67 16 f6 e8 ca 73 48 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:02:24.063726] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:24.063747] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:24.063780] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 C4 68 71 36 D7 8F 0F F6 F4 DF 4E 50 E6 C6 35 04 0D 83 F5 30 EA B1 A3 EE EB FC 98 03 5F 82 73 0F C8 88 34 2B 27 EC 76 F1 CC BD 5B 67 16 F6 E8 CA 73 48 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:02:24.063787] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:02:24.063796] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:02:24.063809] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=67 bytes +[2026-02-20T18:02:24.063817] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:02:24.063824] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:02:24.063830] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-58 +[2026-02-20T18:02:24.063838] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:02:24.063845] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:02:24.063854] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:24.063859] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:24.063864] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:02:26.014495] LOG: [GPS SERVICE] Position stream fired: lat=47.34664, lon=-122.22239, accuracy=3.8m +[2026-02-20T18:02:26.207194] LOG: [PING] Ping sent successfully +[2026-02-20T18:02:27.604353] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:02:27.604457] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:27.706292] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:02:27.706418] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:02:27.706441] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:02:27.706458] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:02:27.764641] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff 88 f8 09 00 00 00 74 23 00 00 +[2026-02-20T18:02:27.764770] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:27.764791] LOG: [CONN] Noise floor updated: -117dBm +[2026-02-20T18:02:28.045263] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:02:28.096913] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:02:31.016796] LOG: [GPS SERVICE] Position stream fired: lat=47.34735, lon=-122.22283, accuracy=3.8m +[2026-02-20T18:02:31.209168] LOG: [PING] RX listening window ended +[2026-02-20T18:02:31.209309] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:02:31.209330] LOG: [GRAPH] Recorded txFail event at -117dBm +[2026-02-20T18:02:31.209382] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:02:31.209396] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:02:31.209406] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:02:31.209423] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:02:31.209438] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:02:31.209743] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:02:31.849570] LOG: [CONN] Frame received (137 bytes): 88 31 c6 11 05 06 c4 7e dd cc 79 5c 55 27 41 aa dd 85 83 05 6d df dc 9c cc 4d cf 33 53 f9 7e 4a 25 d6 57 79 79 97 c1 a5 01 e1 2a 82 99 69 0b a1 e2 4f c1 fe e7 12 3d 6f 54 72 3d ab d0 57 ef 97 c5 af b6 45 71 c1 5e 42 5f 04 c9 84 96 2d c6 49 3f 8e 60 5e c1 a8 da b4 b5 bf 46 39 eb cf 3c 33 86 7d c6 d2 7a a2 a7 dd c6 cb e9 87 2a 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6e 64 73 20 45 76 65 72 79 77 68 65 72 65 +[2026-02-20T18:02:31.849609] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:31.849641] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:31.849707] LOG: [RX PARSE] RAW Packet (134 bytes): 11 05 06 C4 7E DD CC 79 5C 55 27 41 AA DD 85 83 05 6D DF DC 9C CC 4D CF 33 53 F9 7E 4A 25 D6 57 79 79 97 C1 A5 01 E1 2A 82 99 69 0B A1 E2 4F C1 FE E7 12 3D 6F 54 72 3D AB D0 57 EF 97 C5 AF B6 45 71 C1 5E 42 5F 04 C9 84 96 2D C6 49 3F 8E 60 5E C1 A8 DA B4 B5 BF 46 39 EB CF 3C 33 86 7D C6 D2 7A A2 A7 DD C6 CB E9 87 2A 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6E 64 73 20 45 76 65 72 79 77 68 65 72 65 +[2026-02-20T18:02:31.849722] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:02:31.849728] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:02:31.849749] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x06, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=127 bytes +[2026-02-20T18:02:31.849759] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 +[2026-02-20T18:02:31.849767] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:31.849775] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:31.849839] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:31.849849] LOG: [RX FILTER] Raw packet (134 bytes): 11 05 06 C4 7E DD CC 79 5C 55 27 41 AA DD 85 83 05 6D DF DC 9C CC 4D CF 33 53 F9 7E 4A 25 D6 57 79 79 97 C1 A5 01 E1 2A 82 99 69 0B A1 E2 4F C1 FE E7 12 3D 6F 54 72 3D AB D0 57 EF 97 C5 AF B6 45 71 C1 5E 42 5F 04 C9 84 96 2D C6 49 3F 8E 60 5E C1 A8 DA B4 B5 BF 46 39 EB CF 3C 33 86 7D C6 D2 7A A2 A7 DD C6 CB E9 87 2A 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6E 64 73 20 45 76 65 72 79 77 68 65 72 65 +[2026-02-20T18:02:31.849866] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 12.25 +[2026-02-20T18:02:31.849875] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:02:31.849881] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:02:31.849889] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:02:31.849896] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:02:31.849974] LOG: [RX FILTER] ADVERT name extracted: "Friends Everywhere" (18 chars) +[2026-02-20T18:02:31.849988] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:02:31.849995] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Friends Everywhere") +[2026-02-20T18:02:31.850069] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=5 +[2026-02-20T18:02:31.850077] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:02:31.850095] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:02:31.850106] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:02:31.850121] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:02:31.850133] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.34735,-122.22283 +[2026-02-20T18:02:31.850146] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:02:31.850159] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34735,-122.22283 (batch tracking: 1 repeaters, rxCount: 12) +[2026-02-20T18:02:31.850175] LOG: [GRAPH] Recorded rx event at -117dBm with 1 repeater(s) +[2026-02-20T18:02:31.850186] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.34735,-122.22283 +[2026-02-20T18:02:31.850491] LOG: [CONN] Frame received (148 bytes): 8a 79 5c 55 27 41 aa dd 85 83 05 6d df dc 9c cc 4d cf 33 53 f9 7e 4a 25 d6 57 79 79 97 c1 a5 01 e1 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 72 69 65 6e 64 73 20 45 76 65 72 79 77 68 65 72 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2a 82 99 69 00 00 00 00 00 00 00 00 35 12 99 69 +[2026-02-20T18:02:31.850533] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:02:31.850544] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:02:32.602856] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:32.657741] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c6 31 09 00 00 00 74 23 00 00 +[2026-02-20T18:02:32.657874] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:32.657895] LOG: [CONN] Noise floor updated: -117dBm +[2026-02-20T18:02:36.210680] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:02:36.210911] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:02:36.210928] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:02:36.708078] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:02:36.708093] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:02:36.708098] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771639656} +[2026-02-20T18:02:36.708102] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:02:36.708106] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:02:36.708476] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:02:36.708486] LOG: [APP] Upload success: +1 items (total: 16) +[2026-02-20T18:02:37.012768] LOG: [GPS SERVICE] Position stream fired: lat=47.34814, lon=-122.22363, accuracy=3.8m +[2026-02-20T18:02:37.012836] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:02:37.012845] LOG: [RX BATCH] Distance check for repeater CC: 105.92m from first observation (threshold=25m) +[2026-02-20T18:02:37.012848] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:02:37.012851] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:02:37.012856] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:02:37.012861] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.34735,-122.22283 +[2026-02-20T18:02:37.012863] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:02:37.012866] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.34735,-122.22283 +[2026-02-20T18:02:37.012872] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:02:37.012876] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:02:37.012879] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=5 +[2026-02-20T18:02:37.012893] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:02:37.012895] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:02:37.573625] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:02:37.573751] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:02:37.573760] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:02:37.574260] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:02:37.602724] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:37.726850] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 09 00 00 00 74 23 00 00 +[2026-02-20T18:02:37.726902] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:37.726909] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:37.816043] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:02:37.816101] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:02:37.816109] LOG: [API] Response (200) in 0.24s: {"success":true,"expires_at":1771639657} +[2026-02-20T18:02:37.816121] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:02:37.816131] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:02:37.816399] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:02:37.816409] LOG: [APP] Upload success: +1 items (total: 17) +[2026-02-20T18:02:42.602875] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:42.734918] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 09 00 00 00 74 23 00 00 +[2026-02-20T18:02:42.735] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:42.735008] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:42.817733] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:02:46.607108] LOG: [CONN] Frame received (138 bytes): 88 32 c5 11 05 7b 17 7e dd cc 5e 12 ee d8 38 b0 24 70 cc 98 26 f0 a0 7d 67 af 2d bb c8 36 ad 7a 0e 4b 8d 52 0f 75 63 aa 94 36 70 e5 45 66 96 0e bd 84 f3 b4 e9 5a 7d 3f bd 9e 4f 61 e0 72 e5 82 99 c1 5a 01 22 8b 57 2b 8a 6f 0f bb c1 3b c0 28 31 2e c9 32 5c 2f 3f c3 e2 69 ac 02 d6 6b 6f 28 18 0d 3e 1a 75 de 10 b9 7f 7d 7a 34 c6 0b 92 00 00 00 00 00 00 00 00 41 6c 65 78 77 61 72 72 69 6f 72 20 52 6f 6f 66 74 6f 70 +[2026-02-20T18:02:46.607146] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:02:46.607171] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:02:46.607225] LOG: [RX PARSE] RAW Packet (135 bytes): 11 05 7B 17 7E DD CC 5E 12 EE D8 38 B0 24 70 CC 98 26 F0 A0 7D 67 AF 2D BB C8 36 AD 7A 0E 4B 8D 52 0F 75 63 AA 94 36 70 E5 45 66 96 0E BD 84 F3 B4 E9 5A 7D 3F BD 9E 4F 61 E0 72 E5 82 99 C1 5A 01 22 8B 57 2B 8A 6F 0F BB C1 3B C0 28 31 2E C9 32 5C 2F 3F C3 E2 69 AC 02 D6 6B 6F 28 18 0D 3E 1A 75 DE 10 B9 7F 7D 7A 34 C6 0B 92 00 00 00 00 00 00 00 00 41 6C 65 78 77 61 72 72 69 6F 72 20 52 6F 6F 66 74 6F 70 +[2026-02-20T18:02:46.607236] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:02:46.607242] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:02:46.607264] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x7b, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=128 bytes +[2026-02-20T18:02:46.607272] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 +[2026-02-20T18:02:46.607280] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:02:46.607286] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:02:46.607336] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:02:46.607344] LOG: [RX FILTER] Raw packet (135 bytes): 11 05 7B 17 7E DD CC 5E 12 EE D8 38 B0 24 70 CC 98 26 F0 A0 7D 67 AF 2D BB C8 36 AD 7A 0E 4B 8D 52 0F 75 63 AA 94 36 70 E5 45 66 96 0E BD 84 F3 B4 E9 5A 7D 3F BD 9E 4F 61 E0 72 E5 82 99 C1 5A 01 22 8B 57 2B 8A 6F 0F BB C1 3B C0 28 31 2E C9 32 5C 2F 3F C3 E2 69 AC 02 D6 6B 6F 28 18 0D 3E 1A 75 DE 10 B9 7F 7D 7A 34 C6 0B 92 00 00 00 00 00 00 00 00 41 6C 65 78 77 61 72 72 69 6F 72 20 52 6F 6F 66 74 6F 70 +[2026-02-20T18:02:46.607356] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 12.5 +[2026-02-20T18:02:46.607363] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:02:46.607368] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:02:46.607376] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:02:46.607380] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:02:46.607461] LOG: [RX FILTER] ADVERT name extracted: "Alexwarrior Rooftop" (19 chars) +[2026-02-20T18:02:46.607470] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:02:46.607476] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Alexwarrior Rooftop") +[2026-02-20T18:02:46.607550] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=5 +[2026-02-20T18:02:46.607559] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:02:46.607569] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:02:46.607578] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:02:46.607595] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:02:46.607604] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.34814,-122.22363 +[2026-02-20T18:02:46.607616] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:02:46.607627] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34814,-122.22363 (batch tracking: 1 repeaters, rxCount: 13) +[2026-02-20T18:02:46.607640] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:02:46.607650] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.34814,-122.22363 +[2026-02-20T18:02:46.607884] LOG: [CONN] Frame received (148 bytes): 8a 5e 12 ee d8 38 b0 24 70 cc 98 26 f0 a0 7d 67 af 2d bb c8 36 ad 7a 0e 4b 8d 52 0f 75 63 aa 94 36 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 6c 65 78 77 61 72 72 69 6f 72 20 52 6f 6f 66 74 6f 70 00 00 00 00 00 00 00 00 00 00 00 00 00 70 e5 45 66 00 00 00 00 00 00 00 00 43 12 99 69 +[2026-02-20T18:02:46.607900] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:02:46.607910] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:02:46.737200] LOG: [GPS SERVICE] Position stream fired: lat=47.34922, lon=-122.22479, accuracy=3.8m +[2026-02-20T18:02:46.737282] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:02:46.737298] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:02:46.737308] LOG: [RX BATCH] Distance check for repeater CC: 149.07m from first observation (threshold=25m) +[2026-02-20T18:02:46.737311] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:02:46.737316] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:02:46.737320] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:02:46.737324] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.34814,-122.22363 +[2026-02-20T18:02:46.737351] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:02:46.737354] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.34814,-122.22363 +[2026-02-20T18:02:46.737362] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:02:46.737368] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:02:46.737372] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=5 +[2026-02-20T18:02:46.737387] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:02:46.737404] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:02:46.737408] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:02:47.603609] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:47.713022] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c5 30 09 00 00 00 75 23 00 00 +[2026-02-20T18:02:47.713167] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:47.713187] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:02:51.755408] LOG: [GPS SERVICE] Position stream fired: lat=47.34981, lon=-122.22544, accuracy=3.8m +[2026-02-20T18:02:52.573612] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:02:52.573745] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:02:52.573751] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:02:52.574186] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:02:52.604149] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:52.755917] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 09 00 00 00 75 23 00 00 +[2026-02-20T18:02:52.756042] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:52.756067] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:52.997860] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:02:52.997920] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:02:52.997937] LOG: [API] Response (200) in 0.42s: {"success":true,"expires_at":1771639672} +[2026-02-20T18:02:52.997950] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:02:52.997969] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:02:52.998263] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:02:52.998281] LOG: [APP] Upload success: +1 items (total: 18) +[2026-02-20T18:02:56.736782] LOG: [GPS SERVICE] Position stream fired: lat=47.35040, lon=-122.22609, accuracy=3.9m +[2026-02-20T18:02:57.603564] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:02:57.603813] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:02:57.763465] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:02:57.763553] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:02:57.763562] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:02:57.763575] LOG: [CONN] Battery updated: 4059mV (88%) +[2026-02-20T18:02:57.825455] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 09 00 00 00 75 23 00 00 +[2026-02-20T18:02:57.825581] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:02:57.825603] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:02:57.999063] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:03:01.210627] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:03:01.210749] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:03:01.210762] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:03:01.210796] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:03:01.210864] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35040, -122.22609 [0.3w]" +[2026-02-20T18:03:01.210873] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:03:01.210877] LOG: [TX LOG] Payload: "@[MapperBot] 47.35040, -122.22609 [0.3w]" +[2026-02-20T18:03:01.210883] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:03:01.210893] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:03:01.210898] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:03:01.210905] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:03:01.210915] LOG: [CONN] Sending ping: @[MapperBot] 47.35040, -122.22609 [0.3w] +[2026-02-20T18:03:01.336597] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:03:01.336641] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:03:01.336651] LOG: [CONN] Received OK response +[2026-02-20T18:03:01.752758] LOG: [GPS SERVICE] Position stream fired: lat=47.35103, lon=-122.22676, accuracy=3.8m +[2026-02-20T18:03:02.325804] LOG: [CONN] Frame received (73 bytes): 88 31 c5 15 01 cc 81 35 0e 8c d5 a2 96 98 9f b5 b2 fd 07 99 bb ff d7 71 1b 2d 03 30 c8 23 f1 f2 14 15 28 47 cc c4 fc 0b ef 3e de 07 10 c6 b5 88 f2 4c e7 b5 22 d6 10 8f 6b 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:03:02.325973] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:03:02.326012] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:03:02.326096] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 35 0E 8C D5 A2 96 98 9F B5 B2 FD 07 99 BB FF D7 71 1B 2D 03 30 C8 23 F1 F2 14 15 28 47 CC C4 FC 0B EF 3E DE 07 10 C6 B5 88 F2 4C E7 B5 22 D6 10 8F 6B 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:03:02.326118] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:03:02.326133] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:03:02.326166] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=67 bytes +[2026-02-20T18:03:02.326185] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:03:02.326195] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:03:02.326211] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-59 +[2026-02-20T18:03:02.326222] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:03:02.326233] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:03:02.326250] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:03:02.326260] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:03:02.326271] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:03:02.602987] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:02.682057] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:02.682123] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:02.682131] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:04.334869] LOG: [PING] Ping sent successfully +[2026-02-20T18:03:06.212397] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:03:06.743853] LOG: [GPS SERVICE] Position stream fired: lat=47.35166, lon=-122.22744, accuracy=3.8m +[2026-02-20T18:03:07.575496] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:03:07.575620] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:03:07.602876] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:07.694922] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:07.695056] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:07.695083] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:09.335600] LOG: [PING] RX listening window ended +[2026-02-20T18:03:09.335664] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:03:09.335675] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:03:09.335702] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:03:09.335709] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:03:09.335713] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:03:09.335720] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:03:09.335727] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:03:09.335846] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:03:11.739034] LOG: [GPS SERVICE] Position stream fired: lat=47.35228, lon=-122.22805, accuracy=3.8m +[2026-02-20T18:03:11.862260] LOG: [CONN] Frame received (87 bytes): 88 2e c4 15 13 62 1f 7e 75 20 20 20 20 20 20 20 20 20 20 20 53 7e 48 cc ca 17 54 6e ed f2 21 c8 48 a2 de de bc d5 4e f3 34 11 a8 c6 ce 07 11 ca 75 a8 7c fb 4c 18 0c 5b 5f ea a6 bd 68 3d bf 59 a9 26 c0 c6 b7 6d 78 29 e4 9c e0 ea c9 59 71 06 81 e8 5f df d6 7a a6 +[2026-02-20T18:03:11.862339] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:03:11.862353] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:03:11.862389] LOG: [RX PARSE] RAW Packet (84 bytes): 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 +[2026-02-20T18:03:11.862399] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:03:11.862404] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:03:11.862421] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x62, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=63 bytes +[2026-02-20T18:03:11.862428] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:03:11.862435] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:03:11.862441] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:03:11.862473] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:03:11.862495] LOG: [RX FILTER] Raw packet (84 bytes): 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 +[2026-02-20T18:03:11.862503] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 11.5 +[2026-02-20T18:03:11.862511] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:03:11.862615] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:03:11.862620] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:03:11.862628] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:03:11.862634] LOG: [RX FILTER] Encrypted message: 60 bytes +[2026-02-20T18:03:11.862639] LOG: [CRYPTO] Decrypting message (60 bytes) +[2026-02-20T18:03:11.862728] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:03:11.862753] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:03:11.862850] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:03:11.862886] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:03:11.862892] LOG: [RX LOG] Dropped packet hex: 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 +[2026-02-20T18:03:12.603948] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:12.675667] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:12.675801] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:12.675821] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:14.336751] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:03:14.336894] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:03:14.336904] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:03:14.767828] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:03:14.767873] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:03:14.767880] LOG: [API] Response (200) in 0.43s: {"success":true,"expires_at":1771639694} +[2026-02-20T18:03:14.767888] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:03:14.767899] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:03:14.768226] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:03:14.768247] LOG: [APP] Upload success: +1 items (total: 19) +[2026-02-20T18:03:16.754776] LOG: [GPS SERVICE] Position stream fired: lat=47.35288, lon=-122.22848, accuracy=3.8m +[2026-02-20T18:03:16.754814] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:03:16.754867] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:03:17.608900] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:17.684608] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:17.684744] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:17.684770] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:19.768683] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:03:21.749952] LOG: [GPS SERVICE] Position stream fired: lat=47.35341, lon=-122.22884, accuracy=3.8m +[2026-02-20T18:03:22.573685] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:03:22.573806] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:03:22.602711] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:22.692452] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:22.692532] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:22.692542] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:03:26.772569] LOG: [GPS SERVICE] Position stream fired: lat=47.35365, lon=-122.22850, accuracy=3.8m +[2026-02-20T18:03:27.602988] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:03:27.603236] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:27.764929] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:03:27.765078] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:03:27.765097] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:03:27.765113] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:03:27.826250] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:27.826370] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:27.826395] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:31.747284] LOG: [GPS SERVICE] Position stream fired: lat=47.35367, lon=-122.22759, accuracy=3.8m +[2026-02-20T18:03:32.602887] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:32.745424] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:32.745559] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:32.745578] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:36.765767] LOG: [GPS SERVICE] Position stream fired: lat=47.35367, lon=-122.22638, accuracy=3.8m +[2026-02-20T18:03:37.574072] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:03:37.574299] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:03:37.604085] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:37.665144] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:37.665282] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:37.665302] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:39.337032] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:03:39.337202] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:03:39.337232] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:03:39.337269] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:03:39.337311] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35367, -122.22638 [0.3w]" +[2026-02-20T18:03:39.337323] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:03:39.337330] LOG: [TX LOG] Payload: "@[MapperBot] 47.35367, -122.22638 [0.3w]" +[2026-02-20T18:03:39.337345] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:03:39.337355] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:03:39.337364] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:03:39.337378] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:03:39.337394] LOG: [CONN] Sending ping: @[MapperBot] 47.35367, -122.22638 [0.3w] +[2026-02-20T18:03:39.523082] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:03:39.523223] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:03:39.523237] LOG: [CONN] Received OK response +[2026-02-20T18:03:40.518211] LOG: [CONN] Frame received (73 bytes): 88 2f c8 15 01 cc 81 f6 89 1c f0 45 81 d7 f4 61 18 9c f8 4d 2b 9e e1 bc 51 8f 30 ae 2f f4 b1 52 29 27 03 04 a5 25 c7 b5 e3 c9 cf 2d 9e e9 99 79 cf ef 80 eb 1b ac 62 06 06 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:03:40.518376] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:03:40.518407] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:03:40.518481] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 F6 89 1C F0 45 81 D7 F4 61 18 9C F8 4D 2B 9E E1 BC 51 8F 30 AE 2F F4 B1 52 29 27 03 04 A5 25 C7 B5 E3 C9 CF 2D 9E E9 99 79 CF EF 80 EB 1B AC 62 06 06 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:03:40.518503] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:03:40.518625] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:03:40.518690] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=67 bytes +[2026-02-20T18:03:40.518702] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:03:40.518709] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:03:40.518724] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-56 +[2026-02-20T18:03:40.518732] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:03:40.518767] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:03:40.518777] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:03:40.518784] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:03:40.518796] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:03:41.778218] LOG: [GPS SERVICE] Position stream fired: lat=47.35369, lon=-122.22518, accuracy=3.8m +[2026-02-20T18:03:42.525248] LOG: [PING] Ping sent successfully +[2026-02-20T18:03:42.603058] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:42.884414] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:42.884571] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:42.884592] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:44.337919] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:03:46.763967] LOG: [GPS SERVICE] Position stream fired: lat=47.35366, lon=-122.22404, accuracy=3.8m +[2026-02-20T18:03:46.764018] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:03:46.764098] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:03:47.525734] LOG: [PING] RX listening window ended +[2026-02-20T18:03:47.525915] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:03:47.525944] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:03:47.526017] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:03:47.526037] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:03:47.526050] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:03:47.526077] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:03:47.526094] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:03:47.529863] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:03:47.603046] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:47.894422] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 09 00 00 00 75 23 00 00 +[2026-02-20T18:03:47.894651] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:47.894673] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:03:50.030029] LOG: [CONN] Frame received (91 bytes): 88 2f c8 15 03 75 7e cc 23 53 d8 8d 38 18 93 9d ce 82 a4 72 bd 69 0a d6 f1 ef 45 b7 69 79 87 2c 71 89 bb c4 06 5a 0c 8a 2e 40 4d 4b 42 31 e4 d1 2d bb 5a 2e 8c 63 ff 1b cf 4a 3c 56 54 04 cb 89 2a c9 91 c8 67 66 1d be d9 f3 1a 34 5d 76 c3 f6 10 1b 79 cb f0 9b f3 bb 2b 9a 97 +[2026-02-20T18:03:50.030149] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:03:50.030174] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:03:50.030247] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 +[2026-02-20T18:03:50.030262] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:03:50.030274] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:03:50.030293] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0x75, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=83 bytes +[2026-02-20T18:03:50.030307] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:03:50.030317] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:03:50.030324] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:03:50.030386] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:03:50.030397] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 +[2026-02-20T18:03:50.030414] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.75 +[2026-02-20T18:03:50.030426] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:03:50.030435] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:03:50.030448] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:03:50.030458] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:03:50.030664] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:03:50.030674] LOG: [RX LOG] Dropped packet hex: 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 +[2026-02-20T18:03:51.761673] LOG: [GPS SERVICE] Position stream fired: lat=47.35364, lon=-122.22300, accuracy=3.8m +[2026-02-20T18:03:52.531222] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:03:52.531483] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:03:52.531501] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:03:52.575422] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:03:52.575523] LOG: [API QUEUE] Upload skipped: already uploading +[2026-02-20T18:03:52.602886] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:52.782650] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 2f 09 00 00 00 76 23 00 00 +[2026-02-20T18:03:52.782697] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:52.782702] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:03:52.976647] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:03:52.976730] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:03:52.976753] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639732} +[2026-02-20T18:03:52.976771] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:03:52.976795] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:03:52.977709] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:03:52.977728] LOG: [APP] Upload success: +1 items (total: 20) +[2026-02-20T18:03:56.748033] LOG: [GPS SERVICE] Position stream fired: lat=47.35364, lon=-122.22210, accuracy=3.8m +[2026-02-20T18:03:57.602648] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:03:57.602747] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:03:57.645369] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:03:57.645465] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:03:57.645478] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:03:57.645495] LOG: [CONN] Battery updated: 4069mV (89%) +[2026-02-20T18:03:57.701773] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 2f 09 00 00 00 76 23 00 00 +[2026-02-20T18:03:57.701839] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:03:57.701848] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:03:57.978865] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:04:00.841708] LOG: [CONN] Frame received (96 bytes): 88 31 c7 15 0a 75 7e 75 20 20 20 75 7e 2a cc 23 53 d8 8d 38 18 93 9d ce 82 a4 72 bd 69 0a d6 f1 ef 45 b7 69 79 87 2c 71 89 bb c4 06 5a 0c 8a 2e 40 4d 4b 42 31 e4 d1 2d bb 5a 2e 8c 63 ff 1b cf 4a 3c 56 54 04 cb 89 2a c9 91 c8 67 66 1d be d9 f3 1a 34 5d 76 c3 f6 10 1b 79 cb f0 9b f3 bb 2b +[2026-02-20T18:04:00.841852] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:00.841887] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:00.841971] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B +[2026-02-20T18:04:00.841994] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:00.842005] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:04:00.842032] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x75, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=81 bytes +[2026-02-20T18:04:00.842047] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:04:00.842062] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:00.842074] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:00.842150] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:00.842297] LOG: [RX FILTER] Raw packet (93 bytes): 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B +[2026-02-20T18:04:00.842349] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 +[2026-02-20T18:04:00.842367] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:04:00.842379] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:00.842395] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:00.842407] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:00.842558] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:00.842572] LOG: [RX LOG] Dropped packet hex: 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B +[2026-02-20T18:04:01.764191] LOG: [GPS SERVICE] Position stream fired: lat=47.35365, lon=-122.22127, accuracy=3.8m +[2026-02-20T18:04:02.605993] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:02.683044] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 09 00 00 00 76 23 00 00 +[2026-02-20T18:04:02.683139] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:02.683153] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:06.758108] LOG: [GPS SERVICE] Position stream fired: lat=47.35368, lon=-122.22033, accuracy=3.8m +[2026-02-20T18:04:07.367676] LOG: [CONN] Frame received (92 bytes): 88 30 c8 15 04 c7 9b dd cc 81 7a 2f 32 aa 19 11 7a ae ff fa 3c 2e a5 30 7b 53 e7 43 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 65 72 d7 56 d4 00 dd 59 24 5a f4 d0 d7 d1 f8 7a ec 88 d2 05 50 2e 05 93 6c f6 47 01 d9 11 94 cf +[2026-02-20T18:04:07.367805] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:07.367837] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:07.367880] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 C7 9B DD CC 81 7A 2F 32 AA 19 11 7A AE FF FA 3C 2E A5 30 7B 53 E7 43 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 65 72 D7 56 D4 00 DD 59 24 5A F4 D0 D7 D1 F8 7A EC 88 D2 05 50 2E 05 93 6C F6 47 01 D9 11 94 CF +[2026-02-20T18:04:07.367892] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:07.367897] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:04:07.367929] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=83 bytes +[2026-02-20T18:04:07.367941] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:04:07.367951] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:07.367961] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:07.368002] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:07.368015] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 C7 9B DD CC 81 7A 2F 32 AA 19 11 7A AE FF FA 3C 2E A5 30 7B 53 E7 43 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 65 72 D7 56 D4 00 DD 59 24 5A F4 D0 D7 D1 F8 7A EC 88 D2 05 50 2E 05 93 6C F6 47 01 D9 11 94 CF +[2026-02-20T18:04:07.368028] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 +[2026-02-20T18:04:07.368042] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:04:07.368048] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:07.368056] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:04:07.368066] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:04:07.368072] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:04:07.368082] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:04:07.368140] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:04:07.368252] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.39362, -122.50339 [..." +[2026-02-20T18:04:07.368263] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:04:07.368271] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:04:07.368289] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 +[2026-02-20T18:04:07.368295] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:04:07.368304] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 +[2026-02-20T18:04:07.368313] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:04:07.368323] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:04:07.368335] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.35368,-122.22033 +[2026-02-20T18:04:07.368344] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:04:07.368356] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35368,-122.22033 (batch tracking: 1 repeaters, rxCount: 14) +[2026-02-20T18:04:07.368367] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:04:07.368388] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.35368,-122.22033 +[2026-02-20T18:04:07.368583] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:04:07.368591] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:04:07.368598] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:04:07.573632] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:04:07.573736] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:04:07.602995] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:07.723629] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 30 09 00 00 00 76 23 00 00 +[2026-02-20T18:04:07.723704] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:07.723719] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:10.364739] LOG: [CONN] Frame received (28 bytes): 88 30 c7 15 04 32 9d dd cc ca c2 eb 86 2a 26 d9 05 50 19 72 38 91 60 83 00 e2 00 a2 +[2026-02-20T18:04:10.364887] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:10.364922] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:10.364964] LOG: [RX PARSE] RAW Packet (25 bytes): 15 04 32 9D DD CC CA C2 EB 86 2A 26 D9 05 50 19 72 38 91 60 83 00 E2 00 A2 +[2026-02-20T18:04:10.364977] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:10.364992] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:04:10.365016] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=19 bytes +[2026-02-20T18:04:10.365035] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:04:10.365048] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:10.365057] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:10.365093] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:10.365110] LOG: [RX FILTER] Raw packet (25 bytes): 15 04 32 9D DD CC CA C2 EB 86 2A 26 D9 05 50 19 72 38 91 60 83 00 E2 00 A2 +[2026-02-20T18:04:10.365126] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 +[2026-02-20T18:04:10.365140] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:04:10.365157] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:10.365167] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:10.365179] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:10.365196] LOG: [RX FILTER] Encrypted message: 16 bytes +[2026-02-20T18:04:10.365207] LOG: [CRYPTO] Decrypting message (16 bytes) +[2026-02-20T18:04:10.365272] LOG: [CRYPTO] Decrypted successfully (16 bytes) +[2026-02-20T18:04:10.365438] LOG: [RX FILTER] Decrypted message (11 chars): "Lilygo1w: T" +[2026-02-20T18:04:10.365461] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:04:10.365477] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:04:10.365508] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 +[2026-02-20T18:04:10.365525] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:04:10.365542] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.0, new=12.0 +[2026-02-20T18:04:10.365570] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:04:10.365589] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.0, current_best=12.0 +[2026-02-20T18:04:11.690496] LOG: [CONN] Frame received (61 bytes): 88 30 c7 15 05 f7 53 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 ef 5c fa 4d f2 e9 3d ab 68 65 0b 73 62 91 38 f9 26 cb a5 5e cc 6e 9f 6c 61 6b 18 6d f9 e6 +[2026-02-20T18:04:11.690612] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:11.690656] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:11.690719] LOG: [RX PARSE] RAW Packet (58 bytes): 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 +[2026-02-20T18:04:11.690735] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:11.690746] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:04:11.690775] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0xf7, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=51 bytes +[2026-02-20T18:04:11.690788] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T18:04:11.690805] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:11.690816] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:11.690875] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:11.690887] LOG: [RX FILTER] Raw packet (58 bytes): 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 +[2026-02-20T18:04:11.690908] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 +[2026-02-20T18:04:11.690922] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:04:11.690933] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:11.690957] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:11.690968] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:11.691143] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:11.691162] LOG: [RX LOG] Dropped packet hex: 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 +[2026-02-20T18:04:11.751175] LOG: [GPS SERVICE] Position stream fired: lat=47.35370, lon=-122.21909, accuracy=3.8m +[2026-02-20T18:04:11.751238] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:04:11.751246] LOG: [RX BATCH] Distance check for repeater CC: 93.74m from first observation (threshold=25m) +[2026-02-20T18:04:11.751251] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:04:11.751254] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:04:11.751258] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:04:11.751264] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.35368,-122.22033 +[2026-02-20T18:04:11.751267] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:04:11.751271] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.35368,-122.22033 +[2026-02-20T18:04:11.751276] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 +[2026-02-20T18:04:11.751280] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:04:11.751284] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 +[2026-02-20T18:04:11.751298] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:04:11.751300] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:04:12.602889] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:12.644135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 77 23 00 00 +[2026-02-20T18:04:12.644275] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:12.644295] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:16.754591] LOG: [GPS SERVICE] Position stream fired: lat=47.35370, lon=-122.21774, accuracy=3.8m +[2026-02-20T18:04:17.527227] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:04:17.527428] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:04:17.527448] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:04:17.527497] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:04:17.527554] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35370, -122.21774 [0.3w]" +[2026-02-20T18:04:17.527572] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:04:17.527582] LOG: [TX LOG] Payload: "@[MapperBot] 47.35370, -122.21774 [0.3w]" +[2026-02-20T18:04:17.527597] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:04:17.527616] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:04:17.527630] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:04:17.527641] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:04:17.527669] LOG: [CONN] Sending ping: @[MapperBot] 47.35370, -122.21774 [0.3w] +[2026-02-20T18:04:17.602791] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:17.654185] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:04:17.654304] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:04:17.654318] LOG: [CONN] Received OK response +[2026-02-20T18:04:17.712878] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 77 23 00 00 +[2026-02-20T18:04:17.713004] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:17.713026] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:18.268278] LOG: [CONN] Frame received (65 bytes): 88 32 c8 15 0d f7 53 20 20 20 20 20 53 c3 7a 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 ef 5c fa 4d f2 e9 3d ab 68 65 0b 73 62 91 38 f9 26 cb a5 5e cc 6e 9f 6c 61 6b +[2026-02-20T18:04:18.268365] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:18.268381] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:18.268408] LOG: [RX PARSE] RAW Packet (62 bytes): 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B +[2026-02-20T18:04:18.268419] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:18.268423] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:04:18.268439] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=47 bytes +[2026-02-20T18:04:18.268447] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:04:18.268450] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:18.268456] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 +[2026-02-20T18:04:18.268460] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:18.268466] LOG: [TX LOG] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:04:18.268474] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 +[2026-02-20T18:04:18.268478] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:04:18.268483] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:18.268490] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:18.268514] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:18.268518] LOG: [RX FILTER] Raw packet (62 bytes): 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B +[2026-02-20T18:04:18.268527] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.5 +[2026-02-20T18:04:18.268532] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:04:18.268536] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:18.268542] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:18.268548] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:18.268575] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:18.268579] LOG: [RX LOG] Dropped packet hex: 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B +[2026-02-20T18:04:18.800983] LOG: [CONN] Frame received (73 bytes): 88 34 c7 15 01 cc 81 88 5d e5 07 19 0b 64 e1 7d c7 94 e2 77 c9 49 a7 98 43 a0 1d 5a 29 8d b7 bd 90 28 4f 0f 1c 79 bb 02 23 8e 88 50 dd 6c 01 f5 46 6a ce 8f b7 04 36 7c 9a 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:04:18.801164] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:18.801201] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:18.801280] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 88 5D E5 07 19 0B 64 E1 7D C7 94 E2 77 C9 49 A7 98 43 A0 1D 5A 29 8D B7 BD 90 28 4F 0F 1C 79 BB 02 23 8E 88 50 DD 6C 01 F5 46 6A CE 8F B7 04 36 7C 9A 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:04:18.801302] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:18.801313] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:04:18.801352] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=13.0, RSSI=-57, payload=67 bytes +[2026-02-20T18:04:18.801365] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:04:18.801380] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:18.801395] LOG: [TX LOG] Processing rx_log entry: SNR=13.0, RSSI=-57 +[2026-02-20T18:04:18.801405] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:18.801421] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:04:18.801434] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:18.801449] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:18.801462] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:04:20.656765] LOG: [PING] Ping sent successfully +[2026-02-20T18:04:21.179525] LOG: [CONN] Frame received (41 bytes): 88 32 c6 15 13 f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7e dd cc 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 +[2026-02-20T18:04:21.179615] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:21.179633] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:21.179654] LOG: [RX PARSE] RAW Packet (38 bytes): 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 +[2026-02-20T18:04:21.179662] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:21.179668] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:04:21.179679] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=17 bytes +[2026-02-20T18:04:21.179687] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:04:21.179691] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:21.179696] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 +[2026-02-20T18:04:21.179705] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:21.179711] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:21.179718] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x19, expected=0x81 +[2026-02-20T18:04:21.179723] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:04:21.179728] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:21.179736] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:21.179756] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:21.179761] LOG: [RX FILTER] Raw packet (38 bytes): 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 +[2026-02-20T18:04:21.179770] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.5 +[2026-02-20T18:04:21.179775] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:21.179780] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:21.179788] LOG: [RX FILTER] Channel hash: 0x19 +[2026-02-20T18:04:21.179793] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 +[2026-02-20T18:04:21.179820] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:21.179824] LOG: [RX LOG] Dropped packet hex: 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 +[2026-02-20T18:04:21.765514] LOG: [GPS SERVICE] Position stream fired: lat=47.35372, lon=-122.21634, accuracy=3.8m +[2026-02-20T18:04:21.765562] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:04:21.765628] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:04:22.008148] LOG: [CONN] Frame received (44 bytes): 88 31 c6 15 12 f7 53 20 20 20 20 20 20 20 20 20 75 26 07 f4 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 +[2026-02-20T18:04:22.008328] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:22.008358] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:22.008405] LOG: [RX PARSE] RAW Packet (41 bytes): 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 +[2026-02-20T18:04:22.008425] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:22.008436] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:04:22.008468] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xf7, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=21 bytes +[2026-02-20T18:04:22.008481] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T18:04:22.008505] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:22.008517] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-58 +[2026-02-20T18:04:22.008528] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:22.008546] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:22.008559] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 +[2026-02-20T18:04:22.008570] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:04:22.008588] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:22.008599] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:22.008640] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:22.008658] LOG: [RX FILTER] Raw packet (41 bytes): 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 +[2026-02-20T18:04:22.008674] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.25 +[2026-02-20T18:04:22.008692] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:22.008703] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:22.008713] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:22.008729] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:22.008779] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:22.008795] LOG: [RX LOG] Dropped packet hex: 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 +[2026-02-20T18:04:22.413007] LOG: [CONN] Frame received (45 bytes): 88 33 c6 15 15 f7 53 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 c7 32 2a dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 +[2026-02-20T18:04:22.413135] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:22.413164] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:22.413212] LOG: [RX PARSE] RAW Packet (42 bytes): 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 +[2026-02-20T18:04:22.413230] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:22.413241] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:04:22.413272] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xf7, lastHop=0xcc, SNR=12.75, RSSI=-58, payload=19 bytes +[2026-02-20T18:04:22.413287] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:04:22.413296] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:22.413311] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-58 +[2026-02-20T18:04:22.413322] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:22.413335] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:22.413352] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 +[2026-02-20T18:04:22.413363] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:04:22.413378] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:22.413389] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:22.413439] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:22.413450] LOG: [RX FILTER] Raw packet (42 bytes): 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 +[2026-02-20T18:04:22.413470] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.75 +[2026-02-20T18:04:22.413482] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:22.413497] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:22.413508] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:22.413518] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:22.413570] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:22.413582] LOG: [RX LOG] Dropped packet hex: 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 +[2026-02-20T18:04:22.528774] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:04:22.573712] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:04:22.573842] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:04:22.573849] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:04:22.574266] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:04:22.602654] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:22.753320] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 33 09 00 00 00 78 23 00 00 +[2026-02-20T18:04:22.753397] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:22.753409] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:23.016480] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:04:23.016567] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:04:23.016584] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639762} +[2026-02-20T18:04:23.016602] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:04:23.016627] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:04:23.017191] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:04:23.017222] LOG: [APP] Upload success: +1 items (total: 21) +[2026-02-20T18:04:25.658942] LOG: [PING] RX listening window ended +[2026-02-20T18:04:25.659108] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:04:25.659142] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:04:25.659218] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:04:25.659231] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:04:25.659248] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:04:25.659272] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:04:25.659293] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:04:25.659999] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:04:26.611030] LOG: [CONN] Frame received (47 bytes): 88 30 c6 15 1d f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2b 97 19 1f ab 7e 2a dd cc 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b +[2026-02-20T18:04:26.611088] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:26.611127] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:26.611174] LOG: [RX PARSE] RAW Packet (44 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B +[2026-02-20T18:04:26.611195] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:26.611207] LOG: [RX PARSE] Path length offset: 1, Path length: 29 +[2026-02-20T18:04:26.611233] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=29, firstHop=0xf7, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=13 bytes +[2026-02-20T18:04:26.611249] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=29 +[2026-02-20T18:04:26.611260] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:26.611276] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:26.611322] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:26.611334] LOG: [RX FILTER] Raw packet (44 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B +[2026-02-20T18:04:26.611355] LOG: [RX FILTER] Header: 0x15 | PathLength: 29 | SNR: 12.0 +[2026-02-20T18:04:26.611370] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:26.611385] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:26.611399] LOG: [RX FILTER] Channel hash: 0x19 +[2026-02-20T18:04:26.611410] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 +[2026-02-20T18:04:26.611577] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:26.611596] LOG: [RX LOG] Dropped packet hex: 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B +[2026-02-20T18:04:26.745194] LOG: [GPS SERVICE] Position stream fired: lat=47.35371, lon=-122.21487, accuracy=3.8m +[2026-02-20T18:04:27.605110] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:04:27.605307] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:27.704931] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:04:27.705030] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:04:27.705047] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:04:27.705059] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:04:27.763572] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 09 00 00 00 78 23 00 00 +[2026-02-20T18:04:27.763649] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:27.763658] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:28.017950] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:04:28.692612] LOG: [CONN] Frame received (41 bytes): 88 32 c4 15 1d f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7e dd cc 19 ad c8 2f 00 d1 d6 +[2026-02-20T18:04:28.692676] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:28.692689] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:28.692701] LOG: [RX PARSE] RAW Packet (38 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 +[2026-02-20T18:04:28.692705] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:28.692710] LOG: [RX PARSE] Path length offset: 1, Path length: 29 +[2026-02-20T18:04:28.692717] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=29, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-60, payload=7 bytes +[2026-02-20T18:04:28.692721] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=29 +[2026-02-20T18:04:28.692725] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:28.692727] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:28.692736] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:28.692742] LOG: [RX FILTER] Raw packet (38 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 +[2026-02-20T18:04:28.692745] LOG: [RX FILTER] Header: 0x15 | PathLength: 29 | SNR: 12.5 +[2026-02-20T18:04:28.692750] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:04:28.692754] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:28.692756] LOG: [RX FILTER] Channel hash: 0x19 +[2026-02-20T18:04:28.692761] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 +[2026-02-20T18:04:28.692776] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:28.692780] LOG: [RX LOG] Dropped packet hex: 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 +[2026-02-20T18:04:30.568477] LOG: [CONN] Frame received (48 bytes): 88 30 c6 15 27 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e e8 48 1b cc ca c2 eb 86 +[2026-02-20T18:04:30.568563] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:30.568585] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:30.568638] LOG: [RX PARSE] RAW Packet (45 bytes): 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 +[2026-02-20T18:04:30.568647] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:30.568652] LOG: [RX PARSE] Path length offset: 1, Path length: 39 +[2026-02-20T18:04:30.568662] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=39, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=4 bytes +[2026-02-20T18:04:30.568671] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=39 +[2026-02-20T18:04:30.568676] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:30.568682] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:30.568706] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:30.568714] LOG: [RX FILTER] Raw packet (45 bytes): 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 +[2026-02-20T18:04:30.568724] LOG: [RX FILTER] Header: 0x15 | PathLength: 39 | SNR: 12.0 +[2026-02-20T18:04:30.568734] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:30.568739] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:30.568746] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:30.568755] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:30.568762] LOG: [RX FILTER] Encrypted message: 1 bytes +[2026-02-20T18:04:30.568769] LOG: [CRYPTO] Decrypting message (1 bytes) +[2026-02-20T18:04:30.568847] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:30.568873] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:30.568994] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:04:30.569036] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:04:30.569044] LOG: [RX LOG] Dropped packet hex: 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 +[2026-02-20T18:04:30.660756] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:04:30.660978] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:04:30.660995] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:04:30.915214] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:04:30.915317] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:04:30.915333] LOG: [API] Response (200) in 0.25s: {"success":true,"expires_at":1771639770} +[2026-02-20T18:04:30.915357] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:04:30.915376] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:04:30.918708] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:04:30.918731] LOG: [APP] Upload success: +1 items (total: 22) +[2026-02-20T18:04:31.772246] LOG: [GPS SERVICE] Position stream fired: lat=47.35378, lon=-122.21333, accuracy=3.8m +[2026-02-20T18:04:32.602951] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:32.713349] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 09 00 00 00 78 23 00 00 +[2026-02-20T18:04:32.713486] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:32.713521] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:32.959017] LOG: [CONN] Frame received (53 bytes): 88 30 c6 15 2c 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e 64 91 f0 a5 7a 7e 2a dd cc ca c2 eb 8e +[2026-02-20T18:04:32.959148] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:32.959174] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:32.959221] LOG: [RX PARSE] RAW Packet (50 bytes): 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E +[2026-02-20T18:04:32.959233] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:32.959241] LOG: [RX PARSE] Path length offset: 1, Path length: 44 +[2026-02-20T18:04:32.959274] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=44, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=4 bytes +[2026-02-20T18:04:32.959285] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=44 +[2026-02-20T18:04:32.959299] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:32.959307] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:32.959347] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:32.959367] LOG: [RX FILTER] Raw packet (50 bytes): 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E +[2026-02-20T18:04:32.959380] LOG: [RX FILTER] Header: 0x15 | PathLength: 44 | SNR: 12.0 +[2026-02-20T18:04:32.959398] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:32.959406] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:32.959414] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:32.959431] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:32.959441] LOG: [RX FILTER] Encrypted message: 1 bytes +[2026-02-20T18:04:32.959453] LOG: [CRYPTO] Decrypting message (1 bytes) +[2026-02-20T18:04:32.959585] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:32.959629] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:32.959866] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:04:32.959945] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:04:32.959954] LOG: [RX LOG] Dropped packet hex: 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E +[2026-02-20T18:04:33.291326] LOG: [CONN] Frame received (51 bytes): 88 2d c6 15 19 f7 53 20 20 20 20 20 20 20 20 20 75 26 07 f4 7e e8 86 75 83 1f ab 7e 1b cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 26 +[2026-02-20T18:04:33.291485] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:33.291515] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:33.291575] LOG: [RX PARSE] RAW Packet (48 bytes): 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 +[2026-02-20T18:04:33.291594] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:33.291606] LOG: [RX PARSE] Path length offset: 1, Path length: 25 +[2026-02-20T18:04:33.291640] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=25, firstHop=0xf7, lastHop=0xcc, SNR=11.25, RSSI=-58, payload=21 bytes +[2026-02-20T18:04:33.291655] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=25 +[2026-02-20T18:04:33.291670] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:33.291681] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:33.291726] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:33.291737] LOG: [RX FILTER] Raw packet (48 bytes): 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 +[2026-02-20T18:04:33.291757] LOG: [RX FILTER] Header: 0x15 | PathLength: 25 | SNR: 11.25 +[2026-02-20T18:04:33.291771] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:04:33.291787] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:33.291797] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:04:33.291808] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:04:33.291869] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:04:33.291885] LOG: [RX LOG] Dropped packet hex: 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 +[2026-02-20T18:04:35.919723] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:04:36.764262] LOG: [GPS SERVICE] Position stream fired: lat=47.35385, lon=-122.21171, accuracy=3.8m +[2026-02-20T18:04:37.574111] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:04:37.574207] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:04:37.602614] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:37.754732] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2d 09 00 00 00 79 23 00 00 +[2026-02-20T18:04:37.754876] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:37.754895] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:41.755836] LOG: [GPS SERVICE] Position stream fired: lat=47.35396, lon=-122.21002, accuracy=3.8m +[2026-02-20T18:04:42.602774] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:42.684276] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 2d 09 00 00 00 79 23 00 00 +[2026-02-20T18:04:42.684345] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:42.684354] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:04:44.161005] LOG: [CONN] Frame received (68 bytes): 88 2f c8 15 3b 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e 64 91 f0 a5 7a cd a4 c9 bb d7 26 56 93 23 46 56 9a a1 0a 43 7e 2a dd cc ca c2 eb 8d +[2026-02-20T18:04:44.161151] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:44.161182] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:44.161252] LOG: [RX PARSE] RAW Packet (65 bytes): 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D +[2026-02-20T18:04:44.161273] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:44.161284] LOG: [RX PARSE] Path length offset: 1, Path length: 59 +[2026-02-20T18:04:44.161315] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=59, firstHop=0x32, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=4 bytes +[2026-02-20T18:04:44.161333] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=59 +[2026-02-20T18:04:44.161344] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:44.161358] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:44.161419] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:44.161445] LOG: [RX FILTER] Raw packet (65 bytes): 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D +[2026-02-20T18:04:44.161462] LOG: [RX FILTER] Header: 0x15 | PathLength: 59 | SNR: 11.75 +[2026-02-20T18:04:44.161483] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:04:44.161495] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:44.161506] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:44.161522] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:44.161536] LOG: [RX FILTER] Encrypted message: 1 bytes +[2026-02-20T18:04:44.161547] LOG: [CRYPTO] Decrypting message (1 bytes) +[2026-02-20T18:04:44.161693] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:44.161743] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:44.161979] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:04:44.162091] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:04:44.162104] LOG: [RX LOG] Dropped packet hex: 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D +[2026-02-20T18:04:46.754008] LOG: [GPS SERVICE] Position stream fired: lat=47.35419, lon=-122.20829, accuracy=3.8m +[2026-02-20T18:04:46.981717] LOG: [CONN] Frame received (45 bytes): 88 30 c7 15 05 5d fb 7e dd cc ca 13 eb b4 d1 24 46 e1 66 8a 6d 05 3d f4 14 58 ab ee d0 d3 6a 12 90 04 6d 23 89 7c 88 f5 3f 65 7d 6d 6b +[2026-02-20T18:04:46.981811] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:46.981830] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:46.981856] LOG: [RX PARSE] RAW Packet (42 bytes): 15 05 5D FB 7E DD CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D 23 89 7C 88 F5 3F 65 7D 6D 6B +[2026-02-20T18:04:46.981866] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:46.981872] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:04:46.981887] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x5d, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=35 bytes +[2026-02-20T18:04:46.981894] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T18:04:46.981902] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:46.981909] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:46.981932] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:46.981940] LOG: [RX FILTER] Raw packet (42 bytes): 15 05 5D FB 7E DD CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D 23 89 7C 88 F5 3F 65 7D 6D 6B +[2026-02-20T18:04:46.981948] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 +[2026-02-20T18:04:46.981956] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:04:46.981965] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:46.981970] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:46.981976] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:46.981986] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:04:46.981991] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:04:46.982032] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:04:46.982168] LOG: [RX FILTER] Decrypted message (17 chars): "AlanHelTxt : T" +[2026-02-20T18:04:46.982181] LOG: [RX FILTER] Printable ratio: 88.2% (threshold: 60.0%) +[2026-02-20T18:04:46.982190] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:04:46.982208] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=5 +[2026-02-20T18:04:46.982215] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:04:46.982224] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 +[2026-02-20T18:04:46.982241] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:04:46.982250] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:04:46.982263] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.35419,-122.20829 +[2026-02-20T18:04:46.982272] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:04:46.982285] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35419,-122.20829 (batch tracking: 1 repeaters, rxCount: 15) +[2026-02-20T18:04:46.982297] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:04:46.982309] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.35419,-122.20829 +[2026-02-20T18:04:47.604857] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:47.772328] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 79 23 00 00 +[2026-02-20T18:04:47.772463] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:47.772480] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:51.764452] LOG: [GPS SERVICE] Position stream fired: lat=47.35461, lon=-122.20671, accuracy=3.8m +[2026-02-20T18:04:51.764503] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:04:51.764513] LOG: [RX BATCH] Distance check for repeater CC: 128.27m from first observation (threshold=25m) +[2026-02-20T18:04:51.764518] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:04:51.764521] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:04:51.764526] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:04:51.764533] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.35419,-122.20829 +[2026-02-20T18:04:51.764536] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:04:51.764542] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.35419,-122.20829 +[2026-02-20T18:04:51.764548] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 +[2026-02-20T18:04:51.764553] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:04:51.764559] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=5 +[2026-02-20T18:04:51.764620] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:04:51.764623] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:04:52.573750] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:04:52.574003] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:04:52.574021] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:04:52.575378] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:04:52.602816] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:52.782380] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 79 23 00 00 +[2026-02-20T18:04:52.782432] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:52.782442] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:53.010493] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:04:53.010609] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:04:53.010627] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639792} +[2026-02-20T18:04:53.010651] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:04:53.010670] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:04:53.013822] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:04:53.013846] LOG: [APP] Upload success: +1 items (total: 23) +[2026-02-20T18:04:54.862925] LOG: [CONN] Frame received (49 bytes): 88 30 c5 15 13 5d fb 7e 75 20 20 20 20 20 20 20 20 20 20 20 53 7e 2a cc ca 13 eb b4 d1 24 46 e1 66 8a 6d 05 3d f4 14 58 ab ee d0 d3 6a 12 90 04 6d +[2026-02-20T18:04:54.863106] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:54.863136] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:54.863193] LOG: [RX PARSE] RAW Packet (46 bytes): 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D +[2026-02-20T18:04:54.863208] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:54.863219] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:04:54.863247] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x5d, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=25 bytes +[2026-02-20T18:04:54.863261] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:04:54.863278] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:54.863287] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:54.863331] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:54.863348] LOG: [RX FILTER] Raw packet (46 bytes): 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D +[2026-02-20T18:04:54.863365] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.0 +[2026-02-20T18:04:54.863393] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:04:54.863405] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:54.863415] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:54.863432] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:54.863445] LOG: [RX FILTER] Encrypted message: 22 bytes +[2026-02-20T18:04:54.863455] LOG: [CRYPTO] Decrypting message (22 bytes) +[2026-02-20T18:04:54.863611] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:54.863659] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:04:54.863889] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:04:54.863982] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:04:54.863998] LOG: [RX LOG] Dropped packet hex: 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D +[2026-02-20T18:04:55.560794] LOG: [CONN] Frame received (140 bytes): 88 32 c7 15 04 7a 7e dd cc ca 27 34 c4 62 6b 43 33 d8 d1 b0 ea 45 d6 85 7b d7 47 3c 80 81 ae 33 e3 d3 27 eb 9b 39 b0 a7 cb ea 24 28 d6 fc 20 75 98 4b 87 7c df 0c 01 a8 42 49 ec f2 39 11 a7 32 ba ef 75 31 87 48 8c 62 9a 57 59 32 e9 48 93 22 e4 83 0c 2b 8d c0 c9 df 2b 1b ad f7 b7 32 c3 30 75 b8 a5 72 fc 23 4f fd 61 55 37 cc 2b f2 17 85 da 8c 9c 9e a9 75 17 2b 2c 50 b0 fc 18 47 d7 4d 3c a1 d2 df 62 36 5f 7d 5d 13 1f ce +[2026-02-20T18:04:55.560894] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:55.560911] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:55.560992] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 7A 7E DD CC CA 27 34 C4 62 6B 43 33 D8 D1 B0 EA 45 D6 85 7B D7 47 3C 80 81 AE 33 E3 D3 27 EB 9B 39 B0 A7 CB EA 24 28 D6 FC 20 75 98 4B 87 7C DF 0C 01 A8 42 49 EC F2 39 11 A7 32 BA EF 75 31 87 48 8C 62 9A 57 59 32 E9 48 93 22 E4 83 0C 2B 8D C0 C9 DF 2B 1B AD F7 B7 32 C3 30 75 B8 A5 72 FC 23 4F FD 61 55 37 CC 2B F2 17 85 DA 8C 9C 9E A9 75 17 2B 2C 50 B0 FC 18 47 D7 4D 3C A1 D2 DF 62 36 5F 7D 5D 13 1F CE +[2026-02-20T18:04:55.561004] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:55.561011] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:04:55.561029] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x7a, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=131 bytes +[2026-02-20T18:04:55.561041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:04:55.561045] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:55.561053] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:55.561106] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:04:55.561114] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 7A 7E DD CC CA 27 34 C4 62 6B 43 33 D8 D1 B0 EA 45 D6 85 7B D7 47 3C 80 81 AE 33 E3 D3 27 EB 9B 39 B0 A7 CB EA 24 28 D6 FC 20 75 98 4B 87 7C DF 0C 01 A8 42 49 EC F2 39 11 A7 32 BA EF 75 31 87 48 8C 62 9A 57 59 32 E9 48 93 22 E4 83 0C 2B 8D C0 C9 DF 2B 1B AD F7 B7 32 C3 30 75 B8 A5 72 FC 23 4F FD 61 55 37 CC 2B F2 17 85 DA 8C 9C 9E A9 75 17 2B 2C 50 B0 FC 18 47 D7 4D 3C A1 D2 DF 62 36 5F 7D 5D 13 1F CE +[2026-02-20T18:04:55.561125] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.5 +[2026-02-20T18:04:55.561135] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:04:55.561141] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:04:55.561148] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:04:55.561155] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:04:55.561160] LOG: [RX FILTER] Encrypted message: 128 bytes +[2026-02-20T18:04:55.561167] LOG: [CRYPTO] Decrypting message (128 bytes) +[2026-02-20T18:04:55.561226] LOG: [CRYPTO] Decrypted successfully (128 bytes) +[2026-02-20T18:04:55.561332] LOG: [RX FILTER] Decrypted message (115 chars): "HowlBot: ack @[AlanHelTxt ] | 5d,1f,7a | Path Dist: 69.1km ..." +[2026-02-20T18:04:55.561347] LOG: [RX FILTER] Printable ratio: 96.5% (threshold: 60.0%) +[2026-02-20T18:04:55.561351] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:04:55.561370] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=4 +[2026-02-20T18:04:55.561374] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:04:55.561385] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:04:55.561394] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:04:55.561407] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:04:55.561419] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35461,-122.20671 +[2026-02-20T18:04:55.561428] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:04:55.561444] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35461,-122.20671 (batch tracking: 1 repeaters, rxCount: 16) +[2026-02-20T18:04:55.561456] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:04:55.561466] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35461,-122.20671 +[2026-02-20T18:04:55.660922] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:04:55.661060] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:04:55.661078] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:04:55.661117] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:04:55.661161] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35461, -122.20671 [0.3w]" +[2026-02-20T18:04:55.661173] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:04:55.661188] LOG: [TX LOG] Payload: "@[MapperBot] 47.35461, -122.20671 [0.3w]" +[2026-02-20T18:04:55.661202] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:04:55.661219] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:04:55.661231] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:04:55.661242] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:04:55.661267] LOG: [CONN] Sending ping: @[MapperBot] 47.35461, -122.20671 [0.3w] +[2026-02-20T18:04:55.753448] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:04:55.753577] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:04:55.753590] LOG: [CONN] Received OK response +[2026-02-20T18:04:57.077270] LOG: [GPS SERVICE] Position stream fired: lat=47.35513, lon=-122.20508, accuracy=4.5m +[2026-02-20T18:04:57.077350] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:04:57.077380] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:04:57.077394] LOG: [RX BATCH] Distance check for repeater CC: 135.79m from first observation (threshold=25m) +[2026-02-20T18:04:57.077399] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:04:57.077404] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:04:57.077413] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:04:57.077421] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35461,-122.20671 +[2026-02-20T18:04:57.077429] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:04:57.077434] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35461,-122.20671 +[2026-02-20T18:04:57.077441] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:04:57.077449] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:04:57.077457] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=4 +[2026-02-20T18:04:57.077529] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:04:57.077555] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:04:57.077563] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:04:57.387811] LOG: [CONN] Frame received (73 bytes): 88 30 c7 15 01 cc 81 83 65 93 67 92 c2 fc 2f 19 91 1a 48 d5 30 a4 30 b9 be b0 1c b7 24 8a 2e ea 47 03 36 7d 92 f1 1b 20 8c 65 f1 6a 5a 7a c0 1b 30 12 bb c7 b2 dc ce f1 07 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:04:57.387842] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:04:57.387850] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:04:57.387862] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 83 65 93 67 92 C2 FC 2F 19 91 1A 48 D5 30 A4 30 B9 BE B0 1C B7 24 8A 2E EA 47 03 36 7D 92 F1 1B 20 8C 65 F1 6A 5A 7A C0 1B 30 12 BB C7 B2 DC CE F1 07 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:04:57.387865] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:04:57.387867] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:04:57.387872] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=67 bytes +[2026-02-20T18:04:57.387875] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:04:57.387877] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:04:57.387879] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-57 +[2026-02-20T18:04:57.387881] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:04:57.387883] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:04:57.387885] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:04:57.387887] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:04:57.387889] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:04:57.602812] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:04:57.602952] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:04:57.735610] LOG: [CONN] Frame received (11 bytes): 0c d7 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:04:57.735730] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:04:57.735744] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:04:57.735760] LOG: [CONN] Battery updated: 4055mV (88%) +[2026-02-20T18:04:57.792159] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 +[2026-02-20T18:04:57.792219] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:04:57.792229] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:04:58.015850] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:04:58.756562] LOG: [PING] Ping sent successfully +[2026-02-20T18:05:00.662089] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:05:01.744556] LOG: [GPS SERVICE] Position stream fired: lat=47.35547, lon=-122.20365, accuracy=5.0m +[2026-02-20T18:05:02.602841] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:02.684550] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 +[2026-02-20T18:05:02.684622] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:02.684635] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:03.757836] LOG: [PING] RX listening window ended +[2026-02-20T18:05:03.757964] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:05:03.757991] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:05:03.758057] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:05:03.758077] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:05:03.758092] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:05:03.758120] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:05:03.758136] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:05:03.758585] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:05:06.736170] LOG: [GPS SERVICE] Position stream fired: lat=47.35568, lon=-122.20199, accuracy=5.4m +[2026-02-20T18:05:07.573759] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:05:07.574007] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:05:07.574023] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:05:07.574033] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:05:07.577075] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:05:07.602609] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:07.691038] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 +[2026-02-20T18:05:07.691098] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:07.691105] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:08.126024] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:05:08.126077] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:05:08.126087] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771639807} +[2026-02-20T18:05:08.126099] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:05:08.126108] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:05:08.126720] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:05:08.126732] LOG: [APP] Upload success: +2 items (total: 25) +[2026-02-20T18:05:08.759853] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:05:08.759978] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:05:12.079249] LOG: [GPS SERVICE] Position stream fired: lat=47.35575, lon=-122.20030, accuracy=7.0m +[2026-02-20T18:05:12.604025] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:12.704116] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 +[2026-02-20T18:05:12.704202] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:12.704215] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:13.127633] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:05:16.740522] LOG: [GPS SERVICE] Position stream fired: lat=47.35580, lon=-122.19880, accuracy=5.8m +[2026-02-20T18:05:17.603047] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:17.714785] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 +[2026-02-20T18:05:17.714885] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:17.714900] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:18.050653] LOG: [CONN] Frame received (47 bytes): 88 2f c7 09 06 87 f7 c7 7e 1b cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 36 71 06 99 23 04 c6 3b 7d 4f af +[2026-02-20T18:05:18.050843] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:18.050876] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:18.050928] LOG: [RX PARSE] RAW Packet (44 bytes): 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF +[2026-02-20T18:05:18.050949] LOG: [RX PARSE] Header: 0x09, Route type: 1 +[2026-02-20T18:05:18.050961] LOG: [RX PARSE] Path length offset: 1, Path length: 6 +[2026-02-20T18:05:18.050992] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=6, firstHop=0x87, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=36 bytes +[2026-02-20T18:05:18.051006] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=6 +[2026-02-20T18:05:18.051024] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:18.051037] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:18.051087] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:18.051170] LOG: [RX FILTER] Raw packet (44 bytes): 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF +[2026-02-20T18:05:18.051188] LOG: [RX FILTER] Header: 0x09 | PathLength: 6 | SNR: 11.75 +[2026-02-20T18:05:18.051213] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:05:18.051231] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) +[2026-02-20T18:05:18.051288] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:05:18.051300] LOG: [RX LOG] Dropped packet hex: 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF +[2026-02-20T18:05:21.030305] LOG: [CONN] Frame received (81 bytes): 88 32 c6 15 09 8b 1c ab 5a 53 7e e8 32 cc 81 8c 3d 6c b4 48 5f 14 79 87 9e 99 b0 de dc e8 a3 25 fe 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 f7 23 4d 7a f9 6c ff 26 80 e4 6f 42 ef b1 e4 b5 eb fd 9b 57 27 bc 53 60 10 db 82 15 f7 04 5b c9 +[2026-02-20T18:05:21.030480] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:21.030663] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:21.030726] LOG: [RX PARSE] RAW Packet (78 bytes): 15 09 8B 1C AB 5A 53 7E E8 32 CC 81 8C 3D 6C B4 48 5F 14 79 87 9E 99 B0 DE DC E8 A3 25 FE 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 F7 23 4D 7A F9 6C FF 26 80 E4 6F 42 EF B1 E4 B5 EB FD 9B 57 27 BC 53 60 10 DB 82 15 F7 04 5B C9 +[2026-02-20T18:05:21.030742] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:05:21.030752] LOG: [RX PARSE] Path length offset: 1, Path length: 9 +[2026-02-20T18:05:21.030770] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0x8b, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes +[2026-02-20T18:05:21.030785] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 +[2026-02-20T18:05:21.030793] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:21.030804] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:21.030863] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:21.030872] LOG: [RX FILTER] Raw packet (78 bytes): 15 09 8B 1C AB 5A 53 7E E8 32 CC 81 8C 3D 6C B4 48 5F 14 79 87 9E 99 B0 DE DC E8 A3 25 FE 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 F7 23 4D 7A F9 6C FF 26 80 E4 6F 42 EF B1 E4 B5 EB FD 9B 57 27 BC 53 60 10 DB 82 15 F7 04 5B C9 +[2026-02-20T18:05:21.030890] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 12.5 +[2026-02-20T18:05:21.030902] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:05:21.030910] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:05:21.030924] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:05:21.030934] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:05:21.030947] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:05:21.030959] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:05:21.031032] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:05:21.031176] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.97623, -123.80079 [0.3w]" +[2026-02-20T18:05:21.031197] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:05:21.031211] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:05:21.031236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=9 +[2026-02-20T18:05:21.031247] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:05:21.031270] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:05:21.031284] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:05:21.031299] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:05:21.031319] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35580,-122.19880 +[2026-02-20T18:05:21.031334] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:05:21.031355] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35580,-122.19880 (batch tracking: 1 repeaters, rxCount: 17) +[2026-02-20T18:05:21.031372] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:05:21.031391] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35580,-122.19880 +[2026-02-20T18:05:21.031726] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:05:21.031740] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:05:21.031750] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:05:21.775839] LOG: [GPS SERVICE] Position stream fired: lat=47.35589, lon=-122.19731, accuracy=5.3m +[2026-02-20T18:05:21.775872] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:05:21.775883] LOG: [RX BATCH] Distance check for repeater CC: 113.30m from first observation (threshold=25m) +[2026-02-20T18:05:21.775886] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:05:21.775890] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:05:21.775894] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:05:21.775898] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35580,-122.19880 +[2026-02-20T18:05:21.775902] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:05:21.775905] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35580,-122.19880 +[2026-02-20T18:05:21.775913] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:05:21.775917] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:05:21.775921] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=9 +[2026-02-20T18:05:21.775971] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:05:21.775974] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:05:22.575161] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:05:22.575434] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:05:22.575455] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:05:22.576674] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:05:22.578281] LOG: [CONN] Frame received (50 bytes): 88 30 c6 09 0e 87 f7 c7 7e 75 20 20 20 20 20 20 53 7e cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 36 71 06 99 23 04 +[2026-02-20T18:05:22.578308] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:22.578337] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:22.578390] LOG: [RX PARSE] RAW Packet (47 bytes): 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 +[2026-02-20T18:05:22.578405] LOG: [RX PARSE] Header: 0x09, Route type: 1 +[2026-02-20T18:05:22.578422] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:05:22.578446] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=14, firstHop=0x87, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=31 bytes +[2026-02-20T18:05:22.578465] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=14 +[2026-02-20T18:05:22.578477] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:22.578486] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:22.578611] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:22.578632] LOG: [RX FILTER] Raw packet (47 bytes): 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 +[2026-02-20T18:05:22.578648] LOG: [RX FILTER] Header: 0x09 | PathLength: 14 | SNR: 12.0 +[2026-02-20T18:05:22.578668] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:05:22.578682] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) +[2026-02-20T18:05:22.578762] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:05:22.578769] LOG: [RX LOG] Dropped packet hex: 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 +[2026-02-20T18:05:22.602581] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:22.781818] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 0a 00 00 00 7b 23 00 00 +[2026-02-20T18:05:22.781895] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:22.781905] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:23.031108] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:05:23.031147] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:05:23.031154] LOG: [API] Response (200) in 0.46s: {"success":true,"expires_at":1771639822} +[2026-02-20T18:05:23.031164] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:05:23.031171] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:05:23.031352] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:05:23.031360] LOG: [APP] Upload success: +1 items (total: 26) +[2026-02-20T18:05:26.775390] LOG: [GPS SERVICE] Position stream fired: lat=47.35595, lon=-122.19594, accuracy=4.8m +[2026-02-20T18:05:27.602845] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:05:27.603125] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:27.644525] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:05:27.644611] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:05:27.644622] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:05:27.644631] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T18:05:27.703883] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 30 0a 00 00 00 7b 23 00 00 +[2026-02-20T18:05:27.704023] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:27.704050] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:05:28.031900] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:05:29.991106] LOG: [CONN] Frame received (60 bytes): 88 2f c6 09 18 87 f7 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 c5 75 7e cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 99 23 04 c6 3b 7d +[2026-02-20T18:05:29.991263] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:29.991301] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:29.991360] LOG: [RX PARSE] RAW Packet (57 bytes): 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D +[2026-02-20T18:05:29.991380] LOG: [RX PARSE] Header: 0x09, Route type: 1 +[2026-02-20T18:05:29.991392] LOG: [RX PARSE] Path length offset: 1, Path length: 24 +[2026-02-20T18:05:29.991428] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=24, firstHop=0x87, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=31 bytes +[2026-02-20T18:05:29.991442] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=24 +[2026-02-20T18:05:29.991458] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:29.991469] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:29.991535] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:29.991546] LOG: [RX FILTER] Raw packet (57 bytes): 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D +[2026-02-20T18:05:29.991567] LOG: [RX FILTER] Header: 0x09 | PathLength: 24 | SNR: 11.75 +[2026-02-20T18:05:29.991582] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:05:29.991594] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) +[2026-02-20T18:05:29.991660] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:05:29.991676] LOG: [RX LOG] Dropped packet hex: 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D +[2026-02-20T18:05:31.768349] LOG: [GPS SERVICE] Position stream fired: lat=47.35602, lon=-122.19456, accuracy=4.7m +[2026-02-20T18:05:31.768379] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:05:31.768424] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:05:32.602596] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:32.745912] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 0a 00 00 00 7b 23 00 00 +[2026-02-20T18:05:32.746034] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:32.746054] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:33.758657] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:05:33.758767] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:05:33.758776] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:05:33.758790] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:05:33.758806] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35602, -122.19456 [0.3w]" +[2026-02-20T18:05:33.758808] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:05:33.758810] LOG: [TX LOG] Payload: "@[MapperBot] 47.35602, -122.19456 [0.3w]" +[2026-02-20T18:05:33.758815] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:05:33.758818] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:05:33.758821] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:05:33.758824] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:05:33.758829] LOG: [CONN] Sending ping: @[MapperBot] 47.35602, -122.19456 [0.3w] +[2026-02-20T18:05:33.851034] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:05:33.851090] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:05:33.851095] LOG: [CONN] Received OK response +[2026-02-20T18:05:35.418001] LOG: [CONN] Frame received (73 bytes): 88 32 c8 15 01 cc 81 00 58 4c 82 6a 20 fb 92 79 99 d0 7b e3 72 e3 14 55 b2 b3 02 e5 1b 24 67 87 c6 11 ea f7 80 a4 37 68 d8 99 86 c1 7b fb 90 9b a7 e8 90 59 2b 36 50 bb 74 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:05:35.418160] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:35.418191] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:35.418262] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 00 58 4C 82 6A 20 FB 92 79 99 D0 7B E3 72 E3 14 55 B2 B3 02 E5 1B 24 67 87 C6 11 EA F7 80 A4 37 68 D8 99 86 C1 7B FB 90 9B A7 E8 90 59 2B 36 50 BB 74 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:05:35.418283] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:05:35.418296] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:05:35.418317] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=67 bytes +[2026-02-20T18:05:35.418336] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:05:35.418346] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:05:35.418362] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 +[2026-02-20T18:05:35.418375] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:05:35.418385] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:05:35.418402] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:35.418411] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:35.418421] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:05:36.752127] LOG: [GPS SERVICE] Position stream fired: lat=47.35606, lon=-122.19321, accuracy=4.6m +[2026-02-20T18:05:36.858432] LOG: [PING] Ping sent successfully +[2026-02-20T18:05:37.573713] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:05:37.573886] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:05:37.605362] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:37.723117] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 0a 00 00 00 7b 23 00 00 +[2026-02-20T18:05:37.723261] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:37.723280] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:38.762001] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:05:41.770972] LOG: [GPS SERVICE] Position stream fired: lat=47.35613, lon=-122.19188, accuracy=3.8m +[2026-02-20T18:05:41.861682] LOG: [PING] RX listening window ended +[2026-02-20T18:05:41.861860] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:05:41.861893] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:05:41.861999] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:05:41.862021] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:05:41.862036] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:05:41.862070] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:05:41.862096] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:05:41.863379] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:05:42.450438] LOG: [CONN] Frame received (69 bytes): 88 2f c7 15 0f c6 38 a9 c5 75 20 20 20 75 2b f4 f1 20 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d +[2026-02-20T18:05:42.450651] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:42.450698] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:42.450765] LOG: [RX PARSE] RAW Packet (66 bytes): 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D +[2026-02-20T18:05:42.450788] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:05:42.450801] LOG: [RX PARSE] Path length offset: 1, Path length: 15 +[2026-02-20T18:05:42.450833] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0xc6, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=49 bytes +[2026-02-20T18:05:42.450847] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 +[2026-02-20T18:05:42.450863] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:42.450875] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:42.450942] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:42.450953] LOG: [RX FILTER] Raw packet (66 bytes): 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D +[2026-02-20T18:05:42.450976] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 11.75 +[2026-02-20T18:05:42.450991] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:05:42.451007] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:05:42.451021] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:05:42.451033] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:05:42.451123] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:05:42.451136] LOG: [RX LOG] Dropped packet hex: 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D +[2026-02-20T18:05:42.603161] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:42.791630] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2f 0a 00 00 00 7c 23 00 00 +[2026-02-20T18:05:42.791708] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:42.791718] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:46.770604] LOG: [GPS SERVICE] Position stream fired: lat=47.35618, lon=-122.19050, accuracy=3.8m +[2026-02-20T18:05:46.866557] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:05:46.866703] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:05:46.866714] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:05:47.302996] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:05:47.303089] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:05:47.303104] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639847} +[2026-02-20T18:05:47.303121] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:05:47.303134] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:05:47.303468] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:05:47.303483] LOG: [APP] Upload success: +1 items (total: 27) +[2026-02-20T18:05:47.602806] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:47.653275] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2f 0a 00 00 00 7c 23 00 00 +[2026-02-20T18:05:47.653399] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:47.653418] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:49.110087] LOG: [CONN] Frame received (67 bytes): 88 33 c8 15 15 c6 38 a9 c5 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e +[2026-02-20T18:05:49.110212] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:49.110241] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:49.110289] LOG: [RX PARSE] RAW Packet (64 bytes): 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E +[2026-02-20T18:05:49.110305] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:05:49.110314] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:05:49.110342] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xc6, lastHop=0xcc, SNR=12.75, RSSI=-56, payload=41 bytes +[2026-02-20T18:05:49.110353] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:05:49.110366] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:49.110376] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:49.110431] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:49.110439] LOG: [RX FILTER] Raw packet (64 bytes): 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E +[2026-02-20T18:05:49.110456] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.75 +[2026-02-20T18:05:49.110468] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:05:49.110476] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:05:49.110489] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:05:49.110497] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:05:49.110693] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:05:49.110712] LOG: [RX LOG] Dropped packet hex: 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E +[2026-02-20T18:05:51.769968] LOG: [GPS SERVICE] Position stream fired: lat=47.35641, lon=-122.18916, accuracy=3.8m +[2026-02-20T18:05:52.303710] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:05:52.573549] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:05:52.573575] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:05:52.603001] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:52.755852] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 33 0a 00 00 00 7c 23 00 00 +[2026-02-20T18:05:52.756006] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:52.756025] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:05:56.190657] LOG: [CONN] Frame received (65 bytes): 88 31 c8 15 20 c6 38 a9 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 +[2026-02-20T18:05:56.190830] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:05:56.190864] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:05:56.190934] LOG: [RX PARSE] RAW Packet (62 bytes): 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 +[2026-02-20T18:05:56.190954] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:05:56.190965] LOG: [RX PARSE] Path length offset: 1, Path length: 32 +[2026-02-20T18:05:56.190996] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=32, firstHop=0xc6, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=28 bytes +[2026-02-20T18:05:56.191010] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=32 +[2026-02-20T18:05:56.191025] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:05:56.191037] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:05:56.191092] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:05:56.191108] LOG: [RX FILTER] Raw packet (62 bytes): 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 +[2026-02-20T18:05:56.191125] LOG: [RX FILTER] Header: 0x15 | PathLength: 32 | SNR: 12.25 +[2026-02-20T18:05:56.191144] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:05:56.191155] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:05:56.191165] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:05:56.191180] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:05:56.191247] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:05:56.191259] LOG: [RX LOG] Dropped packet hex: 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 +[2026-02-20T18:05:56.783465] LOG: [GPS SERVICE] Position stream fired: lat=47.35692, lon=-122.18801, accuracy=3.8m +[2026-02-20T18:05:57.604990] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:05:57.605190] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:05:57.733360] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:05:57.733504] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:05:57.733523] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:05:57.733538] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:05:57.798017] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 31 0a 00 00 00 7c 23 00 00 +[2026-02-20T18:05:57.798146] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:05:57.798167] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:02.080600] LOG: [GPS SERVICE] Position stream fired: lat=47.35772, lon=-122.18715, accuracy=3.8m +[2026-02-20T18:06:02.080637] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:06:02.080691] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:06:02.603041] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:02.653240] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 31 0a 00 00 00 7c 23 00 00 +[2026-02-20T18:06:02.653371] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:02.653392] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:02.897370] LOG: [CONN] Frame received (61 bytes): 88 30 c8 15 05 24 6c db 9b cc 23 12 8c 0b d3 15 1a 15 c8 32 e7 b2 31 ba c4 c9 dc 7e 0a 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d f2 ea +[2026-02-20T18:06:02.897456] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:02.897482] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:02.897537] LOG: [RX PARSE] RAW Packet (58 bytes): 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA +[2026-02-20T18:06:02.897549] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:02.897560] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:06:02.897577] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x24, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=51 bytes +[2026-02-20T18:06:02.897591] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T18:06:02.897600] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:02.897607] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:02.897651] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:02.897660] LOG: [RX FILTER] Raw packet (58 bytes): 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA +[2026-02-20T18:06:02.897676] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 +[2026-02-20T18:06:02.897686] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:06:02.897697] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:02.897705] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:06:02.897713] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:06:02.897825] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:06:02.897836] LOG: [RX LOG] Dropped packet hex: 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA +[2026-02-20T18:06:06.420044] LOG: [CONN] Frame received (63 bytes): 88 2f c7 15 07 24 6c 5d 54 1f 9b cc 23 12 8c 0b d3 15 1a 15 c8 32 e7 b2 31 ba c4 c9 dc 7e 0a 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d f2 e9 +[2026-02-20T18:06:06.420096] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:06.420133] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:06.420195] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 +[2026-02-20T18:06:06.420213] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:06.420224] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:06:06.420305] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x24, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=51 bytes +[2026-02-20T18:06:06.420320] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:06:06.420337] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:06.420346] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:06.420472] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:06.420485] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 +[2026-02-20T18:06:06.420507] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.75 +[2026-02-20T18:06:06.420521] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:06:06.420536] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:06.420547] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:06:06.420557] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:06:06.420718] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:06:06.420732] LOG: [RX LOG] Dropped packet hex: 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 +[2026-02-20T18:06:06.744878] LOG: [GPS SERVICE] Position stream fired: lat=47.35859, lon=-122.18674, accuracy=3.8m +[2026-02-20T18:06:07.169875] LOG: [CONN] Frame received (83 bytes): 88 32 c8 15 0b 32 8b 85 28 aa 50 5a 15 7a 7e cc 81 82 a2 42 1d 31 e6 2f 8d 46 05 d6 6c 67 6e 30 b5 25 6a 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 1b 10 d0 d6 d3 ea 68 e4 2e f2 e6 cd 70 03 fd f8 39 b6 0d 55 8a 76 73 42 63 8d ac 80 3f c7 96 ac +[2026-02-20T18:06:07.170002] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:07.170023] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:07.170065] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 32 8B 85 28 AA 50 5A 15 7A 7E CC 81 82 A2 42 1D 31 E6 2F 8D 46 05 D6 6C 67 6E 30 B5 25 6A 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 1B 10 D0 D6 D3 EA 68 E4 2E F2 E6 CD 70 03 FD F8 39 B6 0D 55 8A 76 73 42 63 8D AC 80 3F C7 96 AC +[2026-02-20T18:06:07.170075] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:07.170085] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:06:07.170107] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x32, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=67 bytes +[2026-02-20T18:06:07.170117] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:06:07.170124] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:07.170129] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:07.170166] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:07.170173] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 32 8B 85 28 AA 50 5A 15 7A 7E CC 81 82 A2 42 1D 31 E6 2F 8D 46 05 D6 6C 67 6E 30 B5 25 6A 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 1B 10 D0 D6 D3 EA 68 E4 2E F2 E6 CD 70 03 FD F8 39 B6 0D 55 8A 76 73 42 63 8D AC 80 3F C7 96 AC +[2026-02-20T18:06:07.170187] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 +[2026-02-20T18:06:07.170194] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:06:07.170199] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:07.170208] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:07.170214] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:07.170223] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:06:07.170232] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:06:07.170279] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:06:07.170645] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.98584, -123.80795 [0.3w]" +[2026-02-20T18:06:07.170657] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:06:07.170667] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:06:07.170685] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=11 +[2026-02-20T18:06:07.170693] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:06:07.170704] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:06:07.170716] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:06:07.170727] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:06:07.170799] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35859,-122.18674 +[2026-02-20T18:06:07.170820] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:06:07.170841] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35859,-122.18674 (batch tracking: 1 repeaters, rxCount: 18) +[2026-02-20T18:06:07.170855] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:06:07.170871] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35859,-122.18674 +[2026-02-20T18:06:07.171166] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:06:07.171175] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:06:07.171183] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:06:07.574754] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:06:07.574906] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:06:07.603172] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:07.662267] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 0a 00 00 00 7d 23 00 00 +[2026-02-20T18:06:07.662377] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:07.662401] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:11.764446] LOG: [GPS SERVICE] Position stream fired: lat=47.35953, lon=-122.18668, accuracy=3.8m +[2026-02-20T18:06:11.764504] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:06:11.764519] LOG: [RX BATCH] Distance check for repeater CC: 104.04m from first observation (threshold=25m) +[2026-02-20T18:06:11.764523] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:06:11.764533] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:06:11.764541] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:06:11.764547] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35859,-122.18674 +[2026-02-20T18:06:11.764554] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:06:11.764558] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35859,-122.18674 +[2026-02-20T18:06:11.764568] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:06:11.764575] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:06:11.764580] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=11 +[2026-02-20T18:06:11.764668] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:06:11.764672] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:06:11.863208] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:06:11.863362] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:06:11.863387] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:06:11.863433] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:06:11.863483] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35953, -122.18668 [0.3w]" +[2026-02-20T18:06:11.863498] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:06:11.863508] LOG: [TX LOG] Payload: "@[MapperBot] 47.35953, -122.18668 [0.3w]" +[2026-02-20T18:06:11.863526] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:06:11.863539] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:06:11.863557] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:06:11.863571] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:06:11.863592] LOG: [CONN] Sending ping: @[MapperBot] 47.35953, -122.18668 [0.3w] +[2026-02-20T18:06:11.924559] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:06:11.924687] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:06:11.924701] LOG: [CONN] Received OK response +[2026-02-20T18:06:12.602883] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:12.736904] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 32 0a 00 00 00 7d 23 00 00 +[2026-02-20T18:06:12.737049] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:12.737069] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:13.685194] LOG: [CONN] Frame received (73 bytes): 88 2e c6 15 01 cc 81 a4 c4 03 71 4b ac 84 c9 e1 ce 7a 67 fc cc 1b 29 2a 3d 96 ec 08 7f 85 ea 67 0b ab 5d 58 eb 78 ec b7 e8 3d 7a fa 69 77 52 cb b5 e6 d9 e7 3d 59 60 eb c2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:06:13.685356] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:13.685392] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:13.685474] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A4 C4 03 71 4B AC 84 C9 E1 CE 7A 67 FC CC 1B 29 2A 3D 96 EC 08 7F 85 EA 67 0B AB 5D 58 EB 78 EC B7 E8 3D 7A FA 69 77 52 CB B5 E6 D9 E7 3D 59 60 EB C2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:06:13.685490] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:13.685501] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:06:13.685540] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-58, payload=67 bytes +[2026-02-20T18:06:13.685555] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:06:13.685571] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:06:13.685583] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-58 +[2026-02-20T18:06:13.685593] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:06:13.685608] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:06:13.685621] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:13.685637] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:13.685648] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:06:14.924996] LOG: [PING] Ping sent successfully +[2026-02-20T18:06:14.957117] LOG: [CONN] Frame received (76 bytes): 88 2f c6 15 04 15 ae 7e cc 23 f0 81 0e 18 54 5f 26 4c 9d 1a be 81 48 99 c1 80 51 2d f9 bd 90 a6 97 8c 93 fa 4f 1f fd 33 57 46 97 58 b7 ff 85 c2 18 53 10 f9 75 18 63 60 8d c9 c3 86 d2 88 2c 49 a2 25 d3 5d 1e 8a 36 44 99 ee 9e f4 +[2026-02-20T18:06:14.957213] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:14.957235] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:14.957275] LOG: [RX PARSE] RAW Packet (73 bytes): 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 +[2026-02-20T18:06:14.957283] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:14.957292] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:06:14.957307] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=67 bytes +[2026-02-20T18:06:14.957317] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:06:14.957324] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:06:14.957330] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-58 +[2026-02-20T18:06:14.957339] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:06:14.957348] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:06:14.957354] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 +[2026-02-20T18:06:14.957363] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:06:14.957369] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:14.957376] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:14.957411] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:14.957420] LOG: [RX FILTER] Raw packet (73 bytes): 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 +[2026-02-20T18:06:14.957429] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.75 +[2026-02-20T18:06:14.957438] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:06:14.957443] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:14.957451] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:06:14.957458] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:06:14.957495] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:06:14.957508] LOG: [RX LOG] Dropped packet hex: 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 +[2026-02-20T18:06:16.771136] LOG: [GPS SERVICE] Position stream fired: lat=47.36043, lon=-122.18669, accuracy=3.8m +[2026-02-20T18:06:16.864607] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:06:17.603556] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:17.712483] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 2f 0a 00 00 00 7e 23 00 00 +[2026-02-20T18:06:17.712527] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:17.712533] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:19.893267] LOG: [CONN] Frame received (74 bytes): 88 31 c8 15 02 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e 3a d4 39 7c bb af 68 96 77 c1 86 ef b7 91 b3 63 +[2026-02-20T18:06:19.893415] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:19.893444] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:19.893517] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 B3 63 +[2026-02-20T18:06:19.893539] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:19.893550] LOG: [RX PARSE] Path length offset: 1, Path length: 2 +[2026-02-20T18:06:19.893576] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=67 bytes +[2026-02-20T18:06:19.893590] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 +[2026-02-20T18:06:19.893606] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:19.893617] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:19.893682] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:19.893694] LOG: [RX FILTER] Raw packet (71 bytes): 15 02 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 B3 63 +[2026-02-20T18:06:19.893717] LOG: [RX FILTER] Header: 0x15 | PathLength: 2 | SNR: 12.25 +[2026-02-20T18:06:19.893731] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:06:19.893757] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:19.893772] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:19.893784] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:19.893801] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:06:19.893817] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:06:19.893914] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:06:19.894085] LOG: [RX FILTER] Decrypted message (48 chars): "tObLiN: @[MapperBot] 47.62796, -122.15860 [0.3w]" +[2026-02-20T18:06:19.894111] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:06:19.894128] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:06:19.894160] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=2 +[2026-02-20T18:06:19.894172] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:06:19.894187] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:06:19.894209] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:06:19.894228] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:06:19.894254] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36043,-122.18669 +[2026-02-20T18:06:19.894272] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:06:19.894295] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36043,-122.18669 (batch tracking: 1 repeaters, rxCount: 19) +[2026-02-20T18:06:19.894317] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:06:19.894341] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36043,-122.18669 +[2026-02-20T18:06:19.894774] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:06:19.894782] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:06:19.894789] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:06:19.925624] LOG: [PING] RX listening window ended +[2026-02-20T18:06:19.925718] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:06:19.925728] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:06:19.925774] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:06:19.925780] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:06:19.925786] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:06:19.925796] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:06:19.925802] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:06:19.925961] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:06:21.760906] LOG: [GPS SERVICE] Position stream fired: lat=47.36133, lon=-122.18668, accuracy=3.8m +[2026-02-20T18:06:21.761002] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:06:21.761015] LOG: [RX BATCH] Distance check for repeater CC: 99.13m from first observation (threshold=25m) +[2026-02-20T18:06:21.761019] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:06:21.761025] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:06:21.761031] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:06:21.761050] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36043,-122.18669 +[2026-02-20T18:06:21.761054] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:06:21.761058] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36043,-122.18669 +[2026-02-20T18:06:21.761067] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:06:21.761074] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:06:21.761080] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=2 +[2026-02-20T18:06:21.761160] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:06:21.761164] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:06:22.573895] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:06:22.574152] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:06:22.574169] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:06:22.574178] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:06:22.575835] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue +[2026-02-20T18:06:22.603467] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:22.783375] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 31 0a 00 00 00 7e 23 00 00 +[2026-02-20T18:06:22.783497] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:22.783521] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:23.023200] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:06:23.023227] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:06:23.023231] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771639882} +[2026-02-20T18:06:23.023237] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:06:23.023242] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:06:23.023452] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:06:23.023456] LOG: [APP] Upload success: +2 items (total: 29) +[2026-02-20T18:06:24.926744] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:06:24.926863] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:06:24.926870] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:06:25.171880] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:06:25.171993] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:06:25.172010] LOG: [API] Response (200) in 0.24s: {"success":true,"expires_at":1771639885} +[2026-02-20T18:06:25.172034] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:06:25.172052] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:06:25.172427] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:06:25.172444] LOG: [APP] Upload success: +1 items (total: 30) +[2026-02-20T18:06:26.174277] LOG: [CONN] Frame received (80 bytes): 88 32 c7 15 08 7e 6b 22 6e 6b ef 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 ef b7 91 b3 63 +[2026-02-20T18:06:26.174329] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:26.174338] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:26.174357] LOG: [RX PARSE] RAW Packet (77 bytes): 15 08 7E 6B 22 6E 6B EF 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF B7 91 B3 63 +[2026-02-20T18:06:26.174362] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:26.174365] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:06:26.174374] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x7e, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes +[2026-02-20T18:06:26.174376] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:06:26.174381] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:26.174384] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:26.174399] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:26.174404] LOG: [RX FILTER] Raw packet (77 bytes): 15 08 7E 6B 22 6E 6B EF 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF B7 91 B3 63 +[2026-02-20T18:06:26.174409] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.5 +[2026-02-20T18:06:26.174414] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:06:26.174418] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:26.174420] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:26.174425] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:26.174429] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:06:26.174431] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:06:26.174457] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:06:26.174556] LOG: [RX FILTER] Decrypted message (58 chars): "tObLiN: @[MapperBot] 47.62796, -122.15860 [dt" +[2026-02-20T18:06:26.174563] LOG: [RX FILTER] Printable ratio: 77.6% (threshold: 60.0%) +[2026-02-20T18:06:26.174568] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:06:26.174576] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=8 +[2026-02-20T18:06:26.174580] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:06:26.174585] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:06:26.174591] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:06:26.174599] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:06:26.174605] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36133,-122.18668 +[2026-02-20T18:06:26.174610] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:06:26.174615] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36133,-122.18668 (batch tracking: 1 repeaters, rxCount: 20) +[2026-02-20T18:06:26.174622] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:06:26.174627] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36133,-122.18668 +[2026-02-20T18:06:26.753449] LOG: [GPS SERVICE] Position stream fired: lat=47.36222, lon=-122.18667, accuracy=3.8m +[2026-02-20T18:06:26.753505] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:06:26.753516] LOG: [RX BATCH] Distance check for repeater CC: 99.38m from first observation (threshold=25m) +[2026-02-20T18:06:26.753519] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:06:26.753522] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:06:26.753529] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:06:26.753534] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36133,-122.18668 +[2026-02-20T18:06:26.753537] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:06:26.753542] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36133,-122.18668 +[2026-02-20T18:06:26.753548] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:06:26.753554] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:06:26.753560] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=8 +[2026-02-20T18:06:26.753623] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:06:26.753629] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:06:27.602858] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:06:27.603016] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:27.734732] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:06:27.734869] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:06:27.734886] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:06:27.734906] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:06:27.793206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 0a 00 00 00 7e 23 00 00 +[2026-02-20T18:06:27.793337] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:27.793363] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:29.718125] LOG: [CONN] Frame received (65 bytes): 88 30 c6 15 09 93 23 56 1b 5a 53 7e 9b cc ad de 0b c7 7c b5 7d c2 6f 0d b2 2e b9 3c 53 af 5a e3 3b 33 4d ae 57 b4 a8 fb 18 5b f1 92 ed b3 9d 83 c5 35 a1 cb e1 f5 67 aa 4b f0 9a 91 43 29 80 c6 ef +[2026-02-20T18:06:29.718276] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:29.718315] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:29.718380] LOG: [RX PARSE] RAW Packet (62 bytes): 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF +[2026-02-20T18:06:29.718397] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:29.718408] LOG: [RX PARSE] Path length offset: 1, Path length: 9 +[2026-02-20T18:06:29.718453] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0x93, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=51 bytes +[2026-02-20T18:06:29.718467] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 +[2026-02-20T18:06:29.718484] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:29.718494] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:29.718615] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:29.718621] LOG: [RX FILTER] Raw packet (62 bytes): 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF +[2026-02-20T18:06:29.718632] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 12.0 +[2026-02-20T18:06:29.718638] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:06:29.718660] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:29.718665] LOG: [RX FILTER] Channel hash: 0xad +[2026-02-20T18:06:29.718671] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad +[2026-02-20T18:06:29.718706] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:06:29.718714] LOG: [RX LOG] Dropped packet hex: 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF +[2026-02-20T18:06:30.172851] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:06:31.756775] LOG: [GPS SERVICE] Position stream fired: lat=47.36312, lon=-122.18666, accuracy=3.8m +[2026-02-20T18:06:32.602956] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:32.776438] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c6 30 0a 00 00 00 7e 23 00 00 +[2026-02-20T18:06:32.776514] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:32.776524] LOG: [CONN] Noise floor updated: -117dBm +[2026-02-20T18:06:33.901708] LOG: [CONN] Frame received (83 bytes): 88 31 c2 15 0d 7e 75 20 20 20 75 c5 26 07 a5 e8 9b cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e 3a d4 39 7c bb af 68 96 77 c1 86 ef b7 91 +[2026-02-20T18:06:33.901854] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:33.901888] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:33.901977] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 +[2026-02-20T18:06:33.902] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:33.902012] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:06:33.902044] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=65 bytes +[2026-02-20T18:06:33.902063] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:06:33.902075] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:33.902090] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:33.902165] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:33.902178] LOG: [RX FILTER] Raw packet (80 bytes): 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 +[2026-02-20T18:06:33.902200] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 +[2026-02-20T18:06:33.902215] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:06:33.902231] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:33.902243] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:33.902254] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:33.902270] LOG: [RX FILTER] Encrypted message: 62 bytes +[2026-02-20T18:06:33.902281] LOG: [CRYPTO] Decrypting message (62 bytes) +[2026-02-20T18:06:33.902465] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:33.902605] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:33.902798] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:06:33.902897] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:06:33.902910] LOG: [RX LOG] Dropped packet hex: 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 +[2026-02-20T18:06:34.577460] LOG: [CONN] Frame received (83 bytes): 88 31 c3 15 0f 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 75 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 ef +[2026-02-20T18:06:34.577625] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:34.577657] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:34.577735] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF +[2026-02-20T18:06:34.577757] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:34.577769] LOG: [RX PARSE] Path length offset: 1, Path length: 15 +[2026-02-20T18:06:34.577797] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=63 bytes +[2026-02-20T18:06:34.577811] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 +[2026-02-20T18:06:34.577826] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:34.577837] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:34.577939] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:34.577956] LOG: [RX FILTER] Raw packet (80 bytes): 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF +[2026-02-20T18:06:34.577976] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 12.25 +[2026-02-20T18:06:34.578005] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:06:34.578019] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:34.578030] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:34.578049] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:34.578063] LOG: [RX FILTER] Encrypted message: 60 bytes +[2026-02-20T18:06:34.578079] LOG: [CRYPTO] Decrypting message (60 bytes) +[2026-02-20T18:06:34.578255] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:34.578303] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:34.578595] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:06:34.578781] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:06:34.578794] LOG: [RX LOG] Dropped packet hex: 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF +[2026-02-20T18:06:36.765536] LOG: [GPS SERVICE] Position stream fired: lat=47.36400, lon=-122.18664, accuracy=4.3m +[2026-02-20T18:06:36.765589] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:06:36.765647] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:06:37.573648] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:06:37.573809] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:06:37.573816] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:06:37.574233] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:06:37.604869] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:37.788001] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0a 00 00 00 7f 23 00 00 +[2026-02-20T18:06:37.788131] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:37.788156] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:38.181451] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:06:38.181543] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:06:38.181566] LOG: [API] Response (200) in 0.61s: {"success":true,"expires_at":1771639897} +[2026-02-20T18:06:38.181585] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:06:38.181609] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:06:38.182336] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:06:38.182374] LOG: [APP] Upload success: +1 items (total: 31) +[2026-02-20T18:06:41.751307] LOG: [GPS SERVICE] Position stream fired: lat=47.36489, lon=-122.18663, accuracy=4.0m +[2026-02-20T18:06:42.604718] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:43.183346] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:06:43.530197] LOG: [CONN] Frame received (136 bytes): 88 31 c2 11 06 14 62 64 c7 9b cc bc 36 f1 2d 7e 9d 7d a3 ee 4f b1 81 bb 0f 9d 1b cc 5b 6f 29 38 5a 81 84 01 e8 b5 05 30 b2 9c c1 18 13 99 69 18 51 b3 ee 1f a9 bf 2b 7b 98 d4 50 ec 94 1e e8 0f da aa d8 1c 45 48 7e 05 f7 f8 76 64 7b 06 0c 10 e5 fd 21 e9 d5 55 73 5f 03 18 cd 86 d3 63 45 26 ca a2 51 f4 d6 77 42 b8 aa 11 13 e6 34 36 0e 92 40 8d d0 02 62 19 b1 f8 f0 9f 90 a2 46 49 20 4d 49 4e 49 20 54 45 53 54 +[2026-02-20T18:06:43.530290] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:43.530317] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:43.530403] LOG: [RX PARSE] RAW Packet (133 bytes): 11 06 14 62 64 C7 9B CC BC 36 F1 2D 7E 9D 7D A3 EE 4F B1 81 BB 0F 9D 1B CC 5B 6F 29 38 5A 81 84 01 E8 B5 05 30 B2 9C C1 18 13 99 69 18 51 B3 EE 1F A9 BF 2B 7B 98 D4 50 EC 94 1E E8 0F DA AA D8 1C 45 48 7E 05 F7 F8 76 64 7B 06 0C 10 E5 FD 21 E9 D5 55 73 5F 03 18 CD 86 D3 63 45 26 CA A2 51 F4 D6 77 42 B8 AA 11 13 E6 34 36 0E 92 40 8D D0 02 62 19 B1 F8 F0 9F 90 A2 46 49 20 4D 49 4E 49 20 54 45 53 54 +[2026-02-20T18:06:43.530424] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:06:43.530432] LOG: [RX PARSE] Path length offset: 1, Path length: 6 +[2026-02-20T18:06:43.530455] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=6, firstHop=0x14, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=125 bytes +[2026-02-20T18:06:43.530466] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=6 +[2026-02-20T18:06:43.530479] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:43.530487] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:43.530609] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:43.530624] LOG: [RX FILTER] Raw packet (133 bytes): 11 06 14 62 64 C7 9B CC BC 36 F1 2D 7E 9D 7D A3 EE 4F B1 81 BB 0F 9D 1B CC 5B 6F 29 38 5A 81 84 01 E8 B5 05 30 B2 9C C1 18 13 99 69 18 51 B3 EE 1F A9 BF 2B 7B 98 D4 50 EC 94 1E E8 0F DA AA D8 1C 45 48 7E 05 F7 F8 76 64 7B 06 0C 10 E5 FD 21 E9 D5 55 73 5F 03 18 CD 86 D3 63 45 26 CA A2 51 F4 D6 77 42 B8 AA 11 13 E6 34 36 0E 92 40 8D D0 02 62 19 B1 F8 F0 9F 90 A2 46 49 20 4D 49 4E 49 20 54 45 53 54 +[2026-02-20T18:06:43.530644] LOG: [RX FILTER] Header: 0x11 | PathLength: 6 | SNR: 12.25 +[2026-02-20T18:06:43.530656] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:06:43.530668] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:06:43.530677] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:06:43.530684] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:06:43.530780] LOG: [RX FILTER] ADVERT name extracted: "🐢FI MINI TEST" (14 chars) +[2026-02-20T18:06:43.530797] LOG: [RX FILTER] ADVERT name printable ratio: 85.7% +[2026-02-20T18:06:43.530805] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="🐢FI MINI TEST") +[2026-02-20T18:06:43.530827] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=6 +[2026-02-20T18:06:43.530838] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:06:43.530851] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:06:43.530863] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:06:43.530882] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:06:43.530897] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36489,-122.18663 +[2026-02-20T18:06:43.530914] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:06:43.530929] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36489,-122.18663 (batch tracking: 1 repeaters, rxCount: 21) +[2026-02-20T18:06:43.530949] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:06:43.530965] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36489,-122.18663 +[2026-02-20T18:06:43.540526] LOG: [CONN] Frame received (148 bytes): 8a bc 36 f1 2d 7e 9d 7d a3 ee 4f b1 81 bb 0f 9d 1b cc 5b 6f 29 38 5a 81 84 01 e8 b5 05 30 b2 9c c1 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 9f 90 a2 46 49 20 4d 49 4e 49 20 54 45 53 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 13 99 69 40 8d d0 02 62 19 b1 f8 31 13 99 69 +[2026-02-20T18:06:43.540541] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:06:43.540549] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:06:43.540951] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c1 32 0a 00 00 00 7f 23 00 00 +[2026-02-20T18:06:43.540957] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:43.540962] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:43.541340] LOG: [CONN] Frame received (93 bytes): 88 32 c1 15 1a 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 75 c5 a9 26 07 f4 18 50 7e ef db 9b cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 +[2026-02-20T18:06:43.541353] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:43.541362] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:43.541392] LOG: [RX PARSE] RAW Packet (90 bytes): 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 +[2026-02-20T18:06:43.541400] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:43.541406] LOG: [RX PARSE] Path length offset: 1, Path length: 26 +[2026-02-20T18:06:43.541415] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=26, firstHop=0x7e, lastHop=0xcc, SNR=12.5, RSSI=-63, payload=62 bytes +[2026-02-20T18:06:43.541422] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=26 +[2026-02-20T18:06:43.541425] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:43.541430] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:43.541457] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:43.541460] LOG: [RX FILTER] Raw packet (90 bytes): 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 +[2026-02-20T18:06:43.541469] LOG: [RX FILTER] Header: 0x15 | PathLength: 26 | SNR: 12.5 +[2026-02-20T18:06:43.541474] LOG: [RX FILTER] ✓ RSSI OK (-63 < -30) +[2026-02-20T18:06:43.541480] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:43.541484] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:06:43.541488] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:06:43.541499] LOG: [RX FILTER] Encrypted message: 59 bytes +[2026-02-20T18:06:43.541503] LOG: [CRYPTO] Decrypting message (59 bytes) +[2026-02-20T18:06:43.541573] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:43.541590] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:43.541701] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:06:43.541741] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:06:43.541745] LOG: [RX LOG] Dropped packet hex: 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 +[2026-02-20T18:06:46.764870] LOG: [GPS SERVICE] Position stream fired: lat=47.36568, lon=-122.18657, accuracy=4.0m +[2026-02-20T18:06:46.764915] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:06:46.764925] LOG: [RX BATCH] Distance check for repeater CC: 88.07m from first observation (threshold=25m) +[2026-02-20T18:06:46.764929] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:06:46.764932] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:06:46.764938] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:06:46.764945] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36489,-122.18663 +[2026-02-20T18:06:46.764948] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:06:46.764951] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36489,-122.18663 +[2026-02-20T18:06:46.764958] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:06:46.764962] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:06:46.764967] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=6 +[2026-02-20T18:06:46.765017] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:06:46.765021] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:06:47.603651] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:47.653094] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c1 32 0a 00 00 00 80 23 00 00 +[2026-02-20T18:06:47.653258] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:47.653278] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:49.928194] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:06:49.928368] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:06:49.928388] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:06:49.928443] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:06:49.928489] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36568, -122.18657 [0.3w]" +[2026-02-20T18:06:49.928507] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:06:49.928517] LOG: [TX LOG] Payload: "@[MapperBot] 47.36568, -122.18657 [0.3w]" +[2026-02-20T18:06:49.928532] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:06:49.928551] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:06:49.928564] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:06:49.928574] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:06:49.928604] LOG: [CONN] Sending ping: @[MapperBot] 47.36568, -122.18657 [0.3w] +[2026-02-20T18:06:50.112865] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:06:50.112986] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:06:50.112995] LOG: [CONN] Received OK response +[2026-02-20T18:06:51.260400] LOG: [CONN] Frame received (73 bytes): 88 2f c2 15 01 cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 48 82 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:06:51.260457] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:51.260498] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:51.260567] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:06:51.260588] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:51.260601] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:06:51.260629] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=67 bytes +[2026-02-20T18:06:51.260648] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:06:51.260657] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:06:51.260673] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-62 +[2026-02-20T18:06:51.260683] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:06:51.260693] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:06:51.260803] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:51.260816] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:51.260832] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:06:51.757838] LOG: [GPS SERVICE] Position stream fired: lat=47.36632, lon=-122.18659, accuracy=3.9m +[2026-02-20T18:06:52.574328] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:06:52.574688] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:06:52.574712] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:06:52.575759] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:06:52.602963] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:52.662316] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0b 00 00 00 80 23 00 00 +[2026-02-20T18:06:52.662389] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:52.662402] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:06:53.058226] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:06:53.058311] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:06:53.058327] LOG: [API] Response (200) in 0.48s: {"success":true,"expires_at":1771639912} +[2026-02-20T18:06:53.058351] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:06:53.058370] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:06:53.058801] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:06:53.058820] LOG: [APP] Upload success: +1 items (total: 32) +[2026-02-20T18:06:53.116189] LOG: [PING] Ping sent successfully +[2026-02-20T18:06:53.669607] LOG: [CONN] Frame received (44 bytes): 88 32 c5 15 04 1f ab 7e cc ca 88 50 62 ce b1 0a a1 32 31 e3 7b 98 ca 6a 7b 2e 4e 54 4b 2b 1b 4a 2d 94 83 18 d9 5b 07 a9 92 05 80 49 +[2026-02-20T18:06:53.669702] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:53.669725] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:53.669755] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 1F AB 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 80 49 +[2026-02-20T18:06:53.669763] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:53.669772] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:06:53.669786] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=35 bytes +[2026-02-20T18:06:53.669797] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:06:53.669803] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:06:53.669810] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-59 +[2026-02-20T18:06:53.669825] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:06:53.669833] LOG: [TX LOG] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:06:53.669843] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xca, expected=0x81 +[2026-02-20T18:06:53.669850] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:06:53.669857] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:53.669866] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:53.669894] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:53.669900] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 1F AB 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 80 49 +[2026-02-20T18:06:53.669912] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.5 +[2026-02-20T18:06:53.669920] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:06:53.669928] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:53.669937] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:06:53.669944] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:06:53.669953] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:06:53.669961] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:06:53.670003] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:06:53.670101] LOG: [RX FILTER] Decrypted message (14 chars): "DieterPibbs: T" +[2026-02-20T18:06:53.670115] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:06:53.670121] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:06:53.670140] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=4 +[2026-02-20T18:06:53.670149] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:06:53.670160] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:06:53.670171] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:06:53.670188] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:06:53.670199] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36632,-122.18659 +[2026-02-20T18:06:53.670214] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:06:53.670228] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36632,-122.18659 (batch tracking: 1 repeaters, rxCount: 22) +[2026-02-20T18:06:53.670247] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:06:53.670259] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36632,-122.18659 +[2026-02-20T18:06:54.930319] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:06:56.752927] LOG: [GPS SERVICE] Position stream fired: lat=47.36661, lon=-122.18646, accuracy=3.8m +[2026-02-20T18:06:56.752983] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:06:56.752996] LOG: [RX BATCH] Distance check for repeater CC: 33.60m from first observation (threshold=25m) +[2026-02-20T18:06:56.753] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:06:56.753003] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:06:56.753011] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:06:56.753016] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36632,-122.18659 +[2026-02-20T18:06:56.753021] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:06:56.753027] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36632,-122.18659 +[2026-02-20T18:06:56.753033] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:06:56.753041] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:06:56.753045] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=4 +[2026-02-20T18:06:56.753111] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:06:56.753117] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:06:57.287931] LOG: [CONN] Frame received (63 bytes): 88 31 c9 15 07 c6 38 be 18 50 7e cc 23 bc 62 a5 44 88 7b 01 91 c5 31 2c 43 54 97 3c 90 77 e6 26 70 1d 58 6e 8e 8c 80 77 fa a8 cc f0 2d 19 70 cf 8d 08 b6 c3 db 90 a2 f6 37 60 e9 77 c7 cd 89 +[2026-02-20T18:06:57.288085] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:57.288122] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:57.288182] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 +[2026-02-20T18:06:57.288201] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:57.288213] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:06:57.288250] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xc6, lastHop=0xcc, SNR=12.25, RSSI=-55, payload=51 bytes +[2026-02-20T18:06:57.288265] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:06:57.288276] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:57.288290] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:57.288346] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:57.288362] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 +[2026-02-20T18:06:57.288380] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 +[2026-02-20T18:06:57.288400] LOG: [RX FILTER] ✓ RSSI OK (-55 < -30) +[2026-02-20T18:06:57.288413] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:57.288423] LOG: [RX FILTER] Channel hash: 0x23 +[2026-02-20T18:06:57.288439] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 +[2026-02-20T18:06:57.288510] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:06:57.288522] LOG: [RX LOG] Dropped packet hex: 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 +[2026-02-20T18:06:57.603112] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:06:57.603382] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:06:57.795377] LOG: [CONN] Frame received (11 bytes): 0c cc 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:06:57.795520] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:06:57.795544] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:06:57.795560] LOG: [CONN] Battery updated: 4044mV (87%) +[2026-02-20T18:06:57.854806] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c9 31 0b 00 00 00 81 23 00 00 +[2026-02-20T18:06:57.854928] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:06:57.854955] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:06:57.976614] LOG: [CONN] Frame received (49 bytes): 88 32 cc 15 0b 1f ab 7e 75 20 20 20 53 7a 7e cc ca 88 50 62 ce b1 0a a1 32 31 e3 7b 98 ca 6a 7b 2e 4e 54 4b 2b 1b 4a 2d 94 83 18 d9 5b 07 a9 92 05 +[2026-02-20T18:06:57.976769] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:06:57.976799] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:06:57.976856] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 +[2026-02-20T18:06:57.976871] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:06:57.976887] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:06:57.976910] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-52, payload=33 bytes +[2026-02-20T18:06:57.976928] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:06:57.976940] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:06:57.976950] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:06:57.976994] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:06:57.977009] LOG: [RX FILTER] Raw packet (46 bytes): 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 +[2026-02-20T18:06:57.977026] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 +[2026-02-20T18:06:57.977047] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:06:57.977059] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:06:57.977069] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:06:57.977085] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:06:57.977097] LOG: [RX FILTER] Encrypted message: 30 bytes +[2026-02-20T18:06:57.977112] LOG: [CRYPTO] Decrypting message (30 bytes) +[2026-02-20T18:06:57.977265] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:57.977324] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:06:57.977558] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:06:57.977649] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:06:57.977661] LOG: [RX LOG] Dropped packet hex: 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 +[2026-02-20T18:06:58.059716] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:06:58.116565] LOG: [PING] RX listening window ended +[2026-02-20T18:06:58.116605] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:06:58.116615] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:06:58.116640] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:06:58.116643] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:06:58.116646] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:06:58.116654] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:06:58.116657] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:06:58.116933] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:07:01.752211] LOG: [GPS SERVICE] Position stream fired: lat=47.36658, lon=-122.18597, accuracy=3.8m +[2026-02-20T18:07:02.603038] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:02.683296] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0b 00 00 00 81 23 00 00 +[2026-02-20T18:07:02.683431] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:02.683457] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:03.119021] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:07:03.119261] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:07:03.119278] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:07:03.119297] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:07:03.120330] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:07:03.381586] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:07:03.381614] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:07:03.381618] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771639923} +[2026-02-20T18:07:03.381624] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:07:03.381629] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:07:03.382889] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:07:03.382903] LOG: [APP] Upload success: +2 items (total: 34) +[2026-02-20T18:07:06.749083] LOG: [GPS SERVICE] Position stream fired: lat=47.36625, lon=-122.18500, accuracy=3.8m +[2026-02-20T18:07:07.573882] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:07:07.574066] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:07:07.604745] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:07.693409] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0b 00 00 00 81 23 00 00 +[2026-02-20T18:07:07.693546] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:07.693566] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:08.386586] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:07:08.571794] LOG: [CONN] Frame received (144 bytes): 88 31 c6 15 08 51 01 e0 7a ab 7e 9b cc ca bc 14 56 e3 ea 8c 46 76 17 84 73 e9 3f 9a 38 a3 e2 8b c0 44 4b 24 e7 42 90 5d 57 e1 65 9c 39 47 19 c8 47 24 18 0a e8 7c d5 f7 b2 7e bf b8 68 b9 85 4e 21 50 6d 56 30 1b 69 c9 cd 1a dc d0 93 de 05 6d 57 9f 15 1c f9 32 ed ba 95 a3 9d 72 b4 8e b4 7d 5d 3b 98 1d 7c fc 72 a8 20 cc d9 cd 0a 91 2d a7 8b 42 31 3c 76 9e 11 91 01 b6 f7 8f a9 5d d8 69 e1 84 2c d5 39 38 84 d1 ea 99 09 be 39 f8 de 14 +[2026-02-20T18:07:08.571946] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:08.571983] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:08.572101] LOG: [RX PARSE] RAW Packet (141 bytes): 15 08 51 01 E0 7A AB 7E 9B CC CA BC 14 56 E3 EA 8C 46 76 17 84 73 E9 3F 9A 38 A3 E2 8B C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 47 24 18 0A E8 7C D5 F7 B2 7E BF B8 68 B9 85 4E 21 50 6D 56 30 1B 69 C9 CD 1A DC D0 93 DE 05 6D 57 9F 15 1C F9 32 ED BA 95 A3 9D 72 B4 8E B4 7D 5D 3B 98 1D 7C FC 72 A8 20 CC D9 CD 0A 91 2D A7 8B 42 31 3C 76 9E 11 91 01 B6 F7 8F A9 5D D8 69 E1 84 2C D5 39 38 84 D1 EA 99 09 BE 39 F8 DE 14 +[2026-02-20T18:07:08.572128] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:08.572143] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:07:08.572174] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x51, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=131 bytes +[2026-02-20T18:07:08.572194] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:07:08.572205] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:08.572215] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:08.572388] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:08.572402] LOG: [RX FILTER] Raw packet (141 bytes): 15 08 51 01 E0 7A AB 7E 9B CC CA BC 14 56 E3 EA 8C 46 76 17 84 73 E9 3F 9A 38 A3 E2 8B C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 47 24 18 0A E8 7C D5 F7 B2 7E BF B8 68 B9 85 4E 21 50 6D 56 30 1B 69 C9 CD 1A DC D0 93 DE 05 6D 57 9F 15 1C F9 32 ED BA 95 A3 9D 72 B4 8E B4 7D 5D 3B 98 1D 7C FC 72 A8 20 CC D9 CD 0A 91 2D A7 8B 42 31 3C 76 9E 11 91 01 B6 F7 8F A9 5D D8 69 E1 84 2C D5 39 38 84 D1 EA 99 09 BE 39 F8 DE 14 +[2026-02-20T18:07:08.572430] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 +[2026-02-20T18:07:08.572449] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:07:08.572461] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:08.572472] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:07:08.572488] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:07:08.572500] LOG: [RX FILTER] Encrypted message: 128 bytes +[2026-02-20T18:07:08.572547] LOG: [CRYPTO] Decrypting message (128 bytes) +[2026-02-20T18:07:08.572672] LOG: [CRYPTO] Decrypted successfully (128 bytes) +[2026-02-20T18:07:08.572859] LOG: [RX FILTER] Decrypted message (116 chars): "HowlBot: ack @[DieterPibbs] | 1f,17,53,e0 | Path Dist: 48.8k..." +[2026-02-20T18:07:08.572889] LOG: [RX FILTER] Printable ratio: 98.3% (threshold: 60.0%) +[2026-02-20T18:07:08.572899] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:07:08.572930] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=8 +[2026-02-20T18:07:08.572941] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:07:08.572963] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:07:08.572980] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:07:08.573004] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:07:08.573029] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36625,-122.18500 +[2026-02-20T18:07:08.573053] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:07:08.573077] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36625,-122.18500 (batch tracking: 1 repeaters, rxCount: 23) +[2026-02-20T18:07:08.573105] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:07:08.573125] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36625,-122.18500 +[2026-02-20T18:07:11.777288] LOG: [GPS SERVICE] Position stream fired: lat=47.36590, lon=-122.18396, accuracy=3.8m +[2026-02-20T18:07:11.777334] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:07:11.777351] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:07:11.777358] LOG: [RX BATCH] Distance check for repeater CC: 87.78m from first observation (threshold=25m) +[2026-02-20T18:07:11.777375] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:07:11.777378] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:07:11.777382] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:07:11.777388] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36625,-122.18500 +[2026-02-20T18:07:11.777392] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:07:11.777394] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36625,-122.18500 +[2026-02-20T18:07:11.777402] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:07:11.777407] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:07:11.777412] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=8 +[2026-02-20T18:07:11.777459] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:07:11.777477] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:07:11.777480] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:07:12.603001] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:12.675769] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 31 0b 00 00 00 81 23 00 00 +[2026-02-20T18:07:12.675898] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:12.675917] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:07:13.260303] LOG: [CONN] Frame received (91 bytes): 88 2f c8 15 17 cc 9b e8 86 2b 75 20 20 20 20 20 75 ee 66 6a 82 ea 1f a3 74 41 7e cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 48 82 19 55 94 25 e0 39 e7 92 a9 03 64 ee +[2026-02-20T18:07:13.260429] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:13.260457] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:13.260537] LOG: [RX PARSE] RAW Packet (88 bytes): 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:07:13.260559] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:13.260570] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T18:07:13.260611] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=63 bytes +[2026-02-20T18:07:13.260624] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 +[2026-02-20T18:07:13.260639] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:13.260650] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:13.260662] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B +[2026-02-20T18:07:13.260739] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:13.260751] LOG: [RX FILTER] Raw packet (88 bytes): 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:07:13.260773] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.75 +[2026-02-20T18:07:13.260783] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:07:13.260793] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:13.260808] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:07:13.260820] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:07:13.260832] LOG: [RX FILTER] Encrypted message: 60 bytes +[2026-02-20T18:07:13.260846] LOG: [CRYPTO] Decrypting message (60 bytes) +[2026-02-20T18:07:13.261010] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:13.261062] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:13.261278] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:07:13.261411] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:07:13.261423] LOG: [RX LOG] Dropped packet hex: 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE +[2026-02-20T18:07:16.751993] LOG: [GPS SERVICE] Position stream fired: lat=47.36553, lon=-122.18293, accuracy=3.8m +[2026-02-20T18:07:17.602669] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:17.652414] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 0b 00 00 00 82 23 00 00 +[2026-02-20T18:07:17.652531] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:17.652555] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:21.508306] LOG: [CONN] Frame received (80 bytes): 88 31 c6 15 18 cc 9b e8 86 ab 2a 94 de a4 c9 bb b2 43 bf 23 56 1b 28 aa cd 6c c7 7e cc 81 d2 e7 1b ba a3 5a 7d f4 71 55 4b 1a 67 a7 f5 32 c3 c7 3d d9 b2 9e a4 9c 21 f6 27 6e a8 89 76 75 d7 91 04 00 22 de 0b 01 10 56 25 e6 ce 5b c1 09 9e 28 +[2026-02-20T18:07:21.508327] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:21.508342] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:21.508360] LOG: [RX PARSE] RAW Packet (77 bytes): 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 +[2026-02-20T18:07:21.508365] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:21.508368] LOG: [RX PARSE] Path length offset: 1, Path length: 24 +[2026-02-20T18:07:21.508377] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=24, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=51 bytes +[2026-02-20T18:07:21.508380] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=24 +[2026-02-20T18:07:21.508384] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:21.508386] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:21.508389] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B +[2026-02-20T18:07:21.508406] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:21.508409] LOG: [RX FILTER] Raw packet (77 bytes): 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 +[2026-02-20T18:07:21.508414] LOG: [RX FILTER] Header: 0x15 | PathLength: 24 | SNR: 12.25 +[2026-02-20T18:07:21.508418] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:07:21.508421] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:21.508423] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:07:21.508428] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:07:21.508431] LOG: [RX FILTER] Encrypted message: 48 bytes +[2026-02-20T18:07:21.508433] LOG: [CRYPTO] Decrypting message (48 bytes) +[2026-02-20T18:07:21.508458] LOG: [CRYPTO] Decrypted successfully (48 bytes) +[2026-02-20T18:07:21.508524] LOG: [RX FILTER] Decrypted message (39 chars): "!H|76Qy7Wp[H!d" +[2026-02-20T18:07:21.508531] LOG: [RX FILTER] Printable ratio: 35.9% (threshold: 60.0%) +[2026-02-20T18:07:21.508535] LOG: [RX FILTER] ❌ DROPPED: plaintext not printable +[2026-02-20T18:07:21.508587] LOG: [RX LOG] ❌ Packet dropped: plaintext not printable +[2026-02-20T18:07:21.508592] LOG: [RX LOG] Dropped packet hex: 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 +[2026-02-20T18:07:21.762783] LOG: [GPS SERVICE] Position stream fired: lat=47.36518, lon=-122.18189, accuracy=3.8m +[2026-02-20T18:07:22.574218] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:07:22.574462] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:07:22.574475] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:07:22.576145] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:07:22.602620] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:22.782612] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 0b 00 00 00 82 23 00 00 +[2026-02-20T18:07:22.782769] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:22.782793] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:23.070129] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:07:23.070232] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:07:23.070251] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771639942} +[2026-02-20T18:07:23.070269] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:07:23.070292] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:07:23.070738] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:07:23.070746] LOG: [APP] Upload success: +1 items (total: 35) +[2026-02-20T18:07:25.471584] LOG: [CONN] Frame received (63 bytes): 88 31 c6 15 07 f7 e3 7e 6f e8 9b cc 5b 14 5a d1 b0 ab 86 11 a9 7a 06 24 58 53 d3 7a 92 46 64 7e be 30 9c 11 53 80 4b 00 e7 aa d3 cb 77 64 35 f3 c4 44 03 67 69 a6 2a 98 f1 b0 df 7e 09 cf e3 +[2026-02-20T18:07:25.471781] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:25.471812] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:25.471879] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 +[2026-02-20T18:07:25.471896] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:25.471911] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:07:25.471935] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xf7, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=51 bytes +[2026-02-20T18:07:25.471954] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:07:25.471966] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:25.471975] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:25.472034] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:25.472047] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 +[2026-02-20T18:07:25.472070] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 +[2026-02-20T18:07:25.472085] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:07:25.472101] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:25.472112] LOG: [RX FILTER] Channel hash: 0x5b +[2026-02-20T18:07:25.472123] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x5b +[2026-02-20T18:07:25.472260] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:07:25.472274] LOG: [RX LOG] Dropped packet hex: 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 +[2026-02-20T18:07:26.755263] LOG: [GPS SERVICE] Position stream fired: lat=47.36480, lon=-122.18086, accuracy=3.8m +[2026-02-20T18:07:27.603269] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:07:27.603404] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:27.649166] LOG: [CONN] Frame received (47 bytes): 88 2f c6 15 07 4e dc 1f 7e 52 9b cc ca f7 c9 93 32 3d 47 31 51 b2 d8 02 c7 93 70 84 4b 23 73 86 73 a8 4f 6d 6b c8 2a bb f8 bd a3 94 a5 5b 4b +[2026-02-20T18:07:27.649241] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:27.649258] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:27.649284] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 4E DC 1F 7E 52 9B CC CA F7 C9 93 32 3D 47 31 51 B2 D8 02 C7 93 70 84 4B 23 73 86 73 A8 4F 6D 6B C8 2A BB F8 BD A3 94 A5 5B 4B +[2026-02-20T18:07:27.649294] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:27.649300] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:07:27.649319] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x4e, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=35 bytes +[2026-02-20T18:07:27.649326] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:07:27.649331] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:27.649340] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:27.649365] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:27.649371] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 4E DC 1F 7E 52 9B CC CA F7 C9 93 32 3D 47 31 51 B2 D8 02 C7 93 70 84 4B 23 73 86 73 A8 4F 6D 6B C8 2A BB F8 BD A3 94 A5 5B 4B +[2026-02-20T18:07:27.649383] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.75 +[2026-02-20T18:07:27.649391] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:07:27.649399] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:27.649406] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:07:27.649412] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:07:27.649421] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:07:27.649427] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:07:27.649465] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:07:27.649562] LOG: [RX FILTER] Decrypted message (15 chars): "DieterPibbs1: T" +[2026-02-20T18:07:27.649574] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:07:27.649583] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:07:27.649599] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=7 +[2026-02-20T18:07:27.649609] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:07:27.649619] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 +[2026-02-20T18:07:27.649631] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:07:27.649644] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:07:27.649659] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.36480,-122.18086 +[2026-02-20T18:07:27.649669] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:07:27.649680] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36480,-122.18086 (batch tracking: 1 repeaters, rxCount: 24) +[2026-02-20T18:07:27.649693] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:07:27.649705] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.36480,-122.18086 +[2026-02-20T18:07:27.674261] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:07:27.674303] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:07:27.674311] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:07:27.674317] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:07:27.733205] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c6 2f 0b 00 00 00 82 23 00 00 +[2026-02-20T18:07:27.733343] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:27.733363] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:07:28.072397] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:07:28.118966] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:07:28.119004] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:07:28.119010] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:07:28.119025] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:07:28.119040] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36480, -122.18086 [0.3w]" +[2026-02-20T18:07:28.119044] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:07:28.119046] LOG: [TX LOG] Payload: "@[MapperBot] 47.36480, -122.18086 [0.3w]" +[2026-02-20T18:07:28.119051] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:07:28.119054] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:07:28.119058] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:07:28.119062] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:07:28.119066] LOG: [CONN] Sending ping: @[MapperBot] 47.36480, -122.18086 [0.3w] +[2026-02-20T18:07:28.245140] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:07:28.245237] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:07:28.245247] LOG: [CONN] Received OK response +[2026-02-20T18:07:29.519374] LOG: [CONN] Frame received (73 bytes): 88 32 c6 15 01 cc 81 58 24 86 df eb 48 98 a0 5b 4f cd 25 22 32 90 66 70 76 b3 2f 2c a3 52 ab 74 b0 67 13 86 72 e7 6a 4a 03 3a 3c 17 6a f8 82 15 16 d9 27 e2 42 ed 7b c7 a2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:07:29.519472] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:29.519527] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:29.519582] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 58 24 86 DF EB 48 98 A0 5B 4F CD 25 22 32 90 66 70 76 B3 2F 2C A3 52 AB 74 B0 67 13 86 72 E7 6A 4A 03 3A 3C 17 6A F8 82 15 16 D9 27 E2 42 ED 7B C7 A2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:07:29.519597] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:29.519605] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:07:29.519629] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes +[2026-02-20T18:07:29.519640] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:07:29.519647] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:07:29.519659] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 +[2026-02-20T18:07:29.519667] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:07:29.519674] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:07:29.519687] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:29.519694] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:29.519704] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:07:31.245886] LOG: [PING] Ping sent successfully +[2026-02-20T18:07:31.746811] LOG: [GPS SERVICE] Position stream fired: lat=47.36447, lon=-122.17986, accuracy=3.8m +[2026-02-20T18:07:31.746856] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:07:31.746867] LOG: [RX BATCH] Distance check for repeater CC: 83.75m from first observation (threshold=25m) +[2026-02-20T18:07:31.746870] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:07:31.746873] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:07:31.746879] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:07:31.746885] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.36480,-122.18086 +[2026-02-20T18:07:31.746888] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:07:31.746894] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.36480,-122.18086 +[2026-02-20T18:07:31.746900] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 +[2026-02-20T18:07:31.746906] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:07:31.746911] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=7 +[2026-02-20T18:07:31.746967] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:07:31.746972] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:07:32.606854] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:32.772453] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 32 0b 00 00 00 83 23 00 00 +[2026-02-20T18:07:32.772500] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:32.772506] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:32.957195] LOG: [CONN] Frame received (140 bytes): 88 31 c7 15 04 7a 7e 9b cc ca 82 31 72 2d 6a 6e 0e fd bf f9 30 1c d5 0e 7b f5 2d 46 c0 44 4b 24 e7 42 90 5d 57 e1 65 9c 39 47 19 c8 71 fb 08 84 8e 64 bb 95 0d 86 6c 82 54 d2 66 4c d8 1c 79 c2 92 19 a0 24 78 75 13 4a 5e 33 b0 a5 48 53 d0 1c 76 0f 06 78 25 74 be 8a 89 6d ca d3 b8 14 4f 8c 4e 23 7b a2 f4 42 77 99 d8 d2 e6 cb ad 90 ea c0 8a 4f 41 69 22 3c bc 63 8a a6 25 cb 7e da ab ab 3b cc 3f be ec d3 5c a5 48 9f 37 af +[2026-02-20T18:07:32.957363] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:32.957394] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:32.957526] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 7A 7E 9B CC CA 82 31 72 2D 6A 6E 0E FD BF F9 30 1C D5 0E 7B F5 2D 46 C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 71 FB 08 84 8E 64 BB 95 0D 86 6C 82 54 D2 66 4C D8 1C 79 C2 92 19 A0 24 78 75 13 4A 5E 33 B0 A5 48 53 D0 1C 76 0F 06 78 25 74 BE 8A 89 6D CA D3 B8 14 4F 8C 4E 23 7B A2 F4 42 77 99 D8 D2 E6 CB AD 90 EA C0 8A 4F 41 69 22 3C BC 63 8A A6 25 CB 7E DA AB AB 3B CC 3F BE EC D3 5C A5 48 9F 37 AF +[2026-02-20T18:07:32.957579] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:32.957591] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:07:32.957618] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x7a, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=131 bytes +[2026-02-20T18:07:32.957633] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:07:32.957643] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:07:32.957661] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 +[2026-02-20T18:07:32.957671] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:07:32.957691] LOG: [TX LOG] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:07:32.957704] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xca, expected=0x81 +[2026-02-20T18:07:32.957715] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:07:32.957733] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:32.957743] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:32.957858] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:32.957874] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 7A 7E 9B CC CA 82 31 72 2D 6A 6E 0E FD BF F9 30 1C D5 0E 7B F5 2D 46 C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 71 FB 08 84 8E 64 BB 95 0D 86 6C 82 54 D2 66 4C D8 1C 79 C2 92 19 A0 24 78 75 13 4A 5E 33 B0 A5 48 53 D0 1C 76 0F 06 78 25 74 BE 8A 89 6D CA D3 B8 14 4F 8C 4E 23 7B A2 F4 42 77 99 D8 D2 E6 CB AD 90 EA C0 8A 4F 41 69 22 3C BC 63 8A A6 25 CB 7E DA AB AB 3B CC 3F BE EC D3 5C A5 48 9F 37 AF +[2026-02-20T18:07:32.957902] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.25 +[2026-02-20T18:07:32.957915] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:07:32.957931] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:32.957943] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:07:32.957955] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:07:32.957971] LOG: [RX FILTER] Encrypted message: 128 bytes +[2026-02-20T18:07:32.957984] LOG: [CRYPTO] Decrypting message (128 bytes) +[2026-02-20T18:07:32.958123] LOG: [CRYPTO] Decrypted successfully (128 bytes) +[2026-02-20T18:07:32.958313] LOG: [RX FILTER] Decrypted message (121 chars): "HowlBot: ack @[DieterPibbs1] | 4e,dc,1f,7e,7a | Path Dist: 2..." +[2026-02-20T18:07:32.958340] LOG: [RX FILTER] Printable ratio: 98.3% (threshold: 60.0%) +[2026-02-20T18:07:32.958349] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:07:32.958381] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=4 +[2026-02-20T18:07:32.958397] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:07:32.958420] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:07:32.958437] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:07:32.958463] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:07:32.958484] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36447,-122.17986 +[2026-02-20T18:07:32.958508] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:07:32.958677] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36447,-122.17986 (batch tracking: 1 repeaters, rxCount: 25) +[2026-02-20T18:07:32.958691] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:07:32.958701] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36447,-122.17986 +[2026-02-20T18:07:33.122506] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:07:36.246885] LOG: [PING] RX listening window ended +[2026-02-20T18:07:36.247033] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:07:36.247074] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:07:36.247144] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:07:36.247155] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:07:36.247168] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:07:36.247188] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:07:36.247200] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:07:36.247994] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:07:36.764875] LOG: [GPS SERVICE] Position stream fired: lat=47.36413, lon=-122.17896, accuracy=3.8m +[2026-02-20T18:07:36.764914] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:07:36.764922] LOG: [RX BATCH] Distance check for repeater CC: 77.73m from first observation (threshold=25m) +[2026-02-20T18:07:36.764928] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:07:36.764930] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:07:36.764935] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:07:36.764940] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36447,-122.17986 +[2026-02-20T18:07:36.764943] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:07:36.764948] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36447,-122.17986 +[2026-02-20T18:07:36.764953] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:07:36.764958] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:07:36.764963] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=4 +[2026-02-20T18:07:36.765013] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:07:36.765018] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:07:37.574319] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:07:37.574691] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:07:37.574714] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:07:37.574727] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:07:37.576467] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue +[2026-02-20T18:07:37.602637] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:37.663635] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0b 00 00 00 83 23 00 00 +[2026-02-20T18:07:37.663766] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:37.663785] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:38.069071] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:07:38.069176] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:07:38.069195] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771639957} +[2026-02-20T18:07:38.069221] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:07:38.069239] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:07:38.069961] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:07:38.069979] LOG: [APP] Upload success: +2 items (total: 37) +[2026-02-20T18:07:41.249100] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:07:41.250058] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:07:41.250074] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:07:41.586779] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:07:41.586823] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:07:41.586838] LOG: [API] Response (200) in 0.34s: {"success":true,"expires_at":1771639961} +[2026-02-20T18:07:41.586859] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:07:41.586876] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:07:41.587458] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:07:41.587476] LOG: [APP] Upload success: +1 items (total: 38) +[2026-02-20T18:07:41.748442] LOG: [GPS SERVICE] Position stream fired: lat=47.36384, lon=-122.17816, accuracy=3.9m +[2026-02-20T18:07:42.603060] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:42.673862] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 31 0b 00 00 00 83 23 00 00 +[2026-02-20T18:07:42.673990] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:42.674010] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:07:46.587727] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:07:46.764171] LOG: [GPS SERVICE] Position stream fired: lat=47.36359, lon=-122.17744, accuracy=3.8m +[2026-02-20T18:07:46.764258] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:07:46.764283] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:07:47.602748] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:47.687833] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0b 00 00 00 83 23 00 00 +[2026-02-20T18:07:47.687928] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:47.687948] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:07:48.268168] LOG: [CONN] Frame received (69 bytes): 88 2e c7 15 37 cc 9b e8 86 ab 2a 94 de a4 c9 bb b2 43 bf 23 56 1b 28 aa cd 6c c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 20 ab 7e cc 81 d2 e7 1b ba a3 5a 7d f4 +[2026-02-20T18:07:48.268223] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:48.268237] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:48.268254] LOG: [RX PARSE] RAW Packet (66 bytes): 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 +[2026-02-20T18:07:48.268258] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:48.268262] LOG: [RX PARSE] Path length offset: 1, Path length: 55 +[2026-02-20T18:07:48.268273] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=55, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-57, payload=9 bytes +[2026-02-20T18:07:48.268278] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=55 +[2026-02-20T18:07:48.268282] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:48.268284] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:48.268289] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B +[2026-02-20T18:07:48.268303] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:48.268309] LOG: [RX FILTER] Raw packet (66 bytes): 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 +[2026-02-20T18:07:48.268313] LOG: [RX FILTER] Header: 0x15 | PathLength: 55 | SNR: 11.5 +[2026-02-20T18:07:48.268318] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:07:48.268322] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:48.268324] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:07:48.268331] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:07:48.268334] LOG: [RX FILTER] Encrypted message: 6 bytes +[2026-02-20T18:07:48.268336] LOG: [CRYPTO] Decrypting message (6 bytes) +[2026-02-20T18:07:48.268393] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:48.268407] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:48.268485] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:07:48.268514] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:07:48.268517] LOG: [RX LOG] Dropped packet hex: 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 +[2026-02-20T18:07:51.761356] LOG: [GPS SERVICE] Position stream fired: lat=47.36345, lon=-122.17707, accuracy=3.8m +[2026-02-20T18:07:52.573969] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:07:52.574158] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:07:52.604865] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:52.664578] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 2e 0b 00 00 00 83 23 00 00 +[2026-02-20T18:07:52.664710] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:52.664729] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:07:53.059808] LOG: [CONN] Frame received (87 bytes): 88 30 ca 15 21 cc 9b e8 86 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2b 86 c7 db cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 +[2026-02-20T18:07:53.059923] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:53.059948] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:53.060007] LOG: [RX PARSE] RAW Packet (84 bytes): 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 +[2026-02-20T18:07:53.060026] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:53.060036] LOG: [RX PARSE] Path length offset: 1, Path length: 33 +[2026-02-20T18:07:53.060065] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-54, payload=49 bytes +[2026-02-20T18:07:53.060078] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 +[2026-02-20T18:07:53.060090] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:53.060101] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:53.060111] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B +[2026-02-20T18:07:53.060171] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:53.060181] LOG: [RX FILTER] Raw packet (84 bytes): 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 +[2026-02-20T18:07:53.060199] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 12.0 +[2026-02-20T18:07:53.060208] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:07:53.060216] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:53.060228] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:07:53.060239] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:07:53.060248] LOG: [RX FILTER] Encrypted message: 46 bytes +[2026-02-20T18:07:53.060261] LOG: [CRYPTO] Decrypting message (46 bytes) +[2026-02-20T18:07:53.060396] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:53.060443] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:07:53.060636] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:07:53.060730] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:07:53.060739] LOG: [RX LOG] Dropped packet hex: 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 +[2026-02-20T18:07:57.602850] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:07:57.602918] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:07:57.766635] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:07:57.766694] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:07:57.766700] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:07:57.766704] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:07:57.821184] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff ca 30 0b 00 00 00 84 23 00 00 +[2026-02-20T18:07:57.821240] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:07:57.821248] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:07:59.146048] LOG: [CONN] Frame received (143 bytes): 88 32 bd 11 07 07 2b 83 4f 50 7e cc c0 de cc 5a 28 67 eb da 4e 0d 8b ef 79 30 b0 66 4d c4 9f 14 6f 13 b7 3f 65 d4 f0 47 37 3b 35 a9 84 fb 4c 66 71 a2 5b 45 4c cb b1 42 84 47 99 a4 ce fb 96 8f 7f ed 72 ed a0 a9 e8 6e 87 0b e2 6a 0d 4a e3 95 80 97 22 a9 2b 91 19 b0 44 8e d9 f3 a1 ea 04 97 1c 38 51 70 db 05 d5 af f9 f9 ec c7 c7 8a d0 0e 92 04 9a d7 02 8c 96 b7 f8 4b 69 72 6b 6c 61 6e 64 20 48 69 67 68 6c 61 6e 64 73 20 e2 98 80 +[2026-02-20T18:07:59.146104] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:59.146115] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:59.146139] LOG: [RX PARSE] RAW Packet (140 bytes): 11 07 07 2B 83 4F 50 7E CC C0 DE CC 5A 28 67 EB DA 4E 0D 8B EF 79 30 B0 66 4D C4 9F 14 6F 13 B7 3F 65 D4 F0 47 37 3B 35 A9 84 FB 4C 66 71 A2 5B 45 4C CB B1 42 84 47 99 A4 CE FB 96 8F 7F ED 72 ED A0 A9 E8 6E 87 0B E2 6A 0D 4A E3 95 80 97 22 A9 2B 91 19 B0 44 8E D9 F3 A1 EA 04 97 1C 38 51 70 DB 05 D5 AF F9 F9 EC C7 C7 8A D0 0E 92 04 9A D7 02 8C 96 B7 F8 4B 69 72 6B 6C 61 6E 64 20 48 69 67 68 6C 61 6E 64 73 20 E2 98 80 +[2026-02-20T18:07:59.146145] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:07:59.146149] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:07:59.146156] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=7, firstHop=0x07, lastHop=0xcc, SNR=12.5, RSSI=-67, payload=131 bytes +[2026-02-20T18:07:59.146161] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=7 +[2026-02-20T18:07:59.146164] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:59.146166] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:59.146190] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:59.146192] LOG: [RX FILTER] Raw packet (140 bytes): 11 07 07 2B 83 4F 50 7E CC C0 DE CC 5A 28 67 EB DA 4E 0D 8B EF 79 30 B0 66 4D C4 9F 14 6F 13 B7 3F 65 D4 F0 47 37 3B 35 A9 84 FB 4C 66 71 A2 5B 45 4C CB B1 42 84 47 99 A4 CE FB 96 8F 7F ED 72 ED A0 A9 E8 6E 87 0B E2 6A 0D 4A E3 95 80 97 22 A9 2B 91 19 B0 44 8E D9 F3 A1 EA 04 97 1C 38 51 70 DB 05 D5 AF F9 F9 EC C7 C7 8A D0 0E 92 04 9A D7 02 8C 96 B7 F8 4B 69 72 6B 6C 61 6E 64 20 48 69 67 68 6C 61 6E 64 73 20 E2 98 80 +[2026-02-20T18:07:59.146212] LOG: [RX FILTER] Header: 0x11 | PathLength: 7 | SNR: 12.5 +[2026-02-20T18:07:59.146217] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) +[2026-02-20T18:07:59.146219] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:07:59.146221] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:07:59.146224] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:07:59.146266] LOG: [RX FILTER] ADVERT name extracted: "Kirkland Highlands ☀" (20 chars) +[2026-02-20T18:07:59.146273] LOG: [RX FILTER] ADVERT name printable ratio: 95.0% +[2026-02-20T18:07:59.146275] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Kirkland Highlands ☀") +[2026-02-20T18:07:59.146281] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=7 +[2026-02-20T18:07:59.146283] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:07:59.146286] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:07:59.146292] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:07:59.146296] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:07:59.146301] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:07:59.146305] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:07:59.146311] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36345,-122.17707 (batch tracking: 1 repeaters, rxCount: 26) +[2026-02-20T18:07:59.146317] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:07:59.146324] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:07:59.146432] LOG: [CONN] Frame received (148 bytes): 8a c0 de cc 5a 28 67 eb da 4e 0d 8b ef 79 30 b0 66 4d c4 9f 14 6f 13 b7 3f 65 d4 f0 47 37 3b 35 a9 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4b 69 72 6b 6c 61 6e 64 20 48 69 67 68 6c 61 6e 64 73 20 e2 98 80 00 00 00 00 00 00 00 00 00 00 84 fb 4c 66 04 9a d7 02 8c 96 b7 f8 7d 13 99 69 +[2026-02-20T18:07:59.146437] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:07:59.146440] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:07:59.146575] LOG: [CONN] Frame received (108 bytes): 88 31 bf 15 2a 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 20 20 20 20 75 68 26 07 f4 f1 fd 3e 0c 9f 7b fa 92 6e 6b ef fc 7a 08 24 07 f4 53 7e cc 91 bf 46 dd fc fa 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 86 +[2026-02-20T18:07:59.146580] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:07:59.146583] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:07:59.146600] LOG: [RX PARSE] RAW Packet (105 bytes): 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 +[2026-02-20T18:07:59.146602] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:07:59.146606] LOG: [RX PARSE] Path length offset: 1, Path length: 42 +[2026-02-20T18:07:59.146611] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=42, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-65, payload=61 bytes +[2026-02-20T18:07:59.146615] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=42 +[2026-02-20T18:07:59.146617] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:07:59.146618] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:07:59.146634] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:07:59.146637] LOG: [RX FILTER] Raw packet (105 bytes): 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 +[2026-02-20T18:07:59.146641] LOG: [RX FILTER] Header: 0x15 | PathLength: 42 | SNR: 12.25 +[2026-02-20T18:07:59.146646] LOG: [RX FILTER] ✓ RSSI OK (-65 < -30) +[2026-02-20T18:07:59.146647] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:07:59.146649] LOG: [RX FILTER] Channel hash: 0x91 +[2026-02-20T18:07:59.146653] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x91 +[2026-02-20T18:07:59.146670] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:07:59.146672] LOG: [RX LOG] Dropped packet hex: 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 +[2026-02-20T18:08:02.179083] LOG: [CONN] Frame received (68 bytes): 88 31 bb 15 0c 59 28 59 c9 ab 5a be 7a 18 7e 9b cc 6f ff 19 39 16 8f 78 1c 0c 1c b1 77 b3 09 a7 75 e3 07 6e b7 bc d1 fa d7 52 17 61 0f 04 46 72 8f 56 5e 7e 8d 6f 4d f4 55 5f 6f 11 f0 93 c8 9a d1 aa 35 80 +[2026-02-20T18:08:02.179124] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:02.179156] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:02.179205] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 +[2026-02-20T18:08:02.179218] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:02.179229] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:08:02.179246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x59, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=51 bytes +[2026-02-20T18:08:02.179260] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:08:02.179269] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:02.179276] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:02.179322] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:02.179340] LOG: [RX FILTER] Raw packet (65 bytes): 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 +[2026-02-20T18:08:02.179353] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 +[2026-02-20T18:08:02.179367] LOG: [RX FILTER] ✓ RSSI OK (-69 < -30) +[2026-02-20T18:08:02.179376] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:02.179384] LOG: [RX FILTER] Channel hash: 0x6f +[2026-02-20T18:08:02.179396] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x6f +[2026-02-20T18:08:02.179534] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:08:02.179574] LOG: [RX LOG] Dropped packet hex: 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 +[2026-02-20T18:08:02.602710] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:02.692089] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bb 31 0b 00 00 00 85 23 00 00 +[2026-02-20T18:08:02.692196] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:02.692211] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:05.207801] LOG: [CONN] Frame received (83 bytes): 88 32 be 15 0b 8d 82 bf 56 1b ab 9e 50 7a 7e cc 81 47 73 b0 cd af 51 79 cc 8f 68 40 9b b7 bb df 60 9b 1f 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 87 10 e7 16 c2 1c 3c a9 be e9 c2 de d6 69 33 4e 75 76 f6 ba 22 fa b0 40 3b 2a 4d 95 e5 2b 5e 5d +[2026-02-20T18:08:05.207972] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:05.208004] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:05.208091] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 8D 82 BF 56 1B AB 9E 50 7A 7E CC 81 47 73 B0 CD AF 51 79 CC 8F 68 40 9B B7 BB DF 60 9B 1F 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 87 10 E7 16 C2 1C 3C A9 BE E9 C2 DE D6 69 33 4E 75 76 F6 BA 22 FA B0 40 3B 2A 4D 95 E5 2B 5E 5D +[2026-02-20T18:08:05.208111] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:05.208128] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:08:05.208161] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x8d, lastHop=0xcc, SNR=12.5, RSSI=-66, payload=67 bytes +[2026-02-20T18:08:05.208181] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:08:05.208196] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:05.208209] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:05.208289] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:05.208301] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 8D 82 BF 56 1B AB 9E 50 7A 7E CC 81 47 73 B0 CD AF 51 79 CC 8F 68 40 9B B7 BB DF 60 9B 1F 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 87 10 E7 16 C2 1C 3C A9 BE E9 C2 DE D6 69 33 4E 75 76 F6 BA 22 FA B0 40 3B 2A 4D 95 E5 2B 5E 5D +[2026-02-20T18:08:05.208325] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 +[2026-02-20T18:08:05.208342] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) +[2026-02-20T18:08:05.208354] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:05.208369] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:08:05.208382] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:08:05.208407] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:08:05.208419] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:08:05.208515] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:08:05.208688] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.99648, -123.82217 [0.3w]" +[2026-02-20T18:08:05.208712] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:08:05.208730] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:08:05.208762] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=11 +[2026-02-20T18:08:05.208776] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:05.208793] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.5, new=12.5 +[2026-02-20T18:08:05.208821] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:05.208840] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.5, current_best=12.5 +[2026-02-20T18:08:05.209285] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:08:05.209298] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:08:05.209323] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:08:06.247856] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:08:06.247996] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:08:06.248025] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:08:06.248061] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:08:06.248102] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36345, -122.17707 [0.3w]" +[2026-02-20T18:08:06.248112] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:08:06.248119] LOG: [TX LOG] Payload: "@[MapperBot] 47.36345, -122.17707 [0.3w]" +[2026-02-20T18:08:06.248134] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:08:06.248144] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:08:06.248166] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:08:06.248174] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:08:06.248190] LOG: [CONN] Sending ping: @[MapperBot] 47.36345, -122.17707 [0.3w] +[2026-02-20T18:08:06.314911] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:08:06.314961] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:08:06.314974] LOG: [CONN] Received OK response +[2026-02-20T18:08:07.573781] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:08:07.573893] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:08:07.602920] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:07.724466] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 32 0b 00 00 00 85 23 00 00 +[2026-02-20T18:08:07.724607] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:07.724633] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:08.452397] LOG: [CONN] Frame received (73 bytes): 88 32 bc 15 01 cc 81 1e d1 16 ff 6a 1c bb 92 54 81 69 10 f6 8d 6a 8d bb ae 17 5a e3 50 16 bb 9d 6c 09 73 f7 8a d9 42 f1 e6 f7 93 92 27 66 39 09 af 0e 95 f7 97 ce 73 73 e4 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:08:08.452554] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:08.452584] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:08.452654] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1E D1 16 FF 6A 1C BB 92 54 81 69 10 F6 8D 6A 8D BB AE 17 5A E3 50 16 BB 9D 6C 09 73 F7 8A D9 42 F1 E6 F7 93 92 27 66 39 09 AF 0E 95 F7 97 CE 73 73 E4 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:08:08.452675] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:08.452686] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:08:08.452714] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-68, payload=67 bytes +[2026-02-20T18:08:08.452730] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:08:08.452740] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:08:08.452758] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-68 +[2026-02-20T18:08:08.452769] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:08:08.452780] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:08:08.452797] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:08.452807] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:08.452825] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:08:09.316800] LOG: [PING] Ping sent successfully +[2026-02-20T18:08:10.183708] LOG: [CONN] Frame received (136 bytes): 88 34 bd 11 0c 11 99 b1 c4 a5 5f 0a 21 e0 cf 7e cc fe 41 d5 5b db 3f 70 63 44 3d cb 58 14 03 b9 4d a6 ea c0 07 7b ea 20 f3 8d 49 a4 00 48 40 ac 75 87 5b 08 00 9a 94 c1 89 32 ae 09 f8 60 d8 48 62 9d 71 c3 12 25 f2 1b 37 9b e0 d3 7f 08 90 dc ff 79 23 33 d7 eb 1b ae 9a 08 4e 30 da 1d 9b 6c b3 f2 3d d1 c8 1b 07 ad e4 e9 84 08 c2 5d ed 9a 53 e1 95 07 0f 92 52 a6 d7 02 0a b2 b4 f8 42 72 65 61 64 68 65 61 64 73 +[2026-02-20T18:08:10.183898] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:10.183930] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:10.184063] LOG: [RX PARSE] RAW Packet (133 bytes): 11 0C 11 99 B1 C4 A5 5F 0A 21 E0 CF 7E CC FE 41 D5 5B DB 3F 70 63 44 3D CB 58 14 03 B9 4D A6 EA C0 07 7B EA 20 F3 8D 49 A4 00 48 40 AC 75 87 5B 08 00 9A 94 C1 89 32 AE 09 F8 60 D8 48 62 9D 71 C3 12 25 F2 1B 37 9B E0 D3 7F 08 90 DC FF 79 23 33 D7 EB 1B AE 9A 08 4E 30 DA 1D 9B 6C B3 F2 3D D1 C8 1B 07 AD E4 E9 84 08 C2 5D ED 9A 53 E1 95 07 0F 92 52 A6 D7 02 0A B2 B4 F8 42 72 65 61 64 68 65 61 64 73 +[2026-02-20T18:08:10.184092] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:08:10.184109] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:08:10.184144] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=12, firstHop=0x11, lastHop=0xcc, SNR=13.0, RSSI=-67, payload=119 bytes +[2026-02-20T18:08:10.184164] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=12 +[2026-02-20T18:08:10.184175] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:08:10.184187] LOG: [TX LOG] Processing rx_log entry: SNR=13.0, RSSI=-67 +[2026-02-20T18:08:10.184203] LOG: [TX LOG] Ignoring: header validation failed (header=0x11) +[2026-02-20T18:08:10.184216] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:10.184231] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:10.184367] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:10.184379] LOG: [RX FILTER] Raw packet (133 bytes): 11 0C 11 99 B1 C4 A5 5F 0A 21 E0 CF 7E CC FE 41 D5 5B DB 3F 70 63 44 3D CB 58 14 03 B9 4D A6 EA C0 07 7B EA 20 F3 8D 49 A4 00 48 40 AC 75 87 5B 08 00 9A 94 C1 89 32 AE 09 F8 60 D8 48 62 9D 71 C3 12 25 F2 1B 37 9B E0 D3 7F 08 90 DC FF 79 23 33 D7 EB 1B AE 9A 08 4E 30 DA 1D 9B 6C B3 F2 3D D1 C8 1B 07 AD E4 E9 84 08 C2 5D ED 9A 53 E1 95 07 0F 92 52 A6 D7 02 0A B2 B4 F8 42 72 65 61 64 68 65 61 64 73 +[2026-02-20T18:08:10.184406] LOG: [RX FILTER] Header: 0x11 | PathLength: 12 | SNR: 13.0 +[2026-02-20T18:08:10.184424] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) +[2026-02-20T18:08:10.184436] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:08:10.184447] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:08:10.184461] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:08:10.184570] LOG: [RX FILTER] ADVERT name extracted: "Breadheads" (10 chars) +[2026-02-20T18:08:10.184586] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:08:10.184612] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Breadheads") +[2026-02-20T18:08:10.184632] LOG: [RX LOG] Packet heard via last hop: CC, SNR=13.0, path_length=12 +[2026-02-20T18:08:10.184648] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:10.184664] LOG: [RX BATCH] Better SNR for repeater CC: 12.5 -> 13.0 +[2026-02-20T18:08:10.184686] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:10.184706] LOG: [APP] Immediate RX observation: repeater=CC, snr=13.0, location=47.36345,-122.17707 +[2026-02-20T18:08:10.184728] LOG: [APP] Current batch tracking: 1 repeaters: {CC} +[2026-02-20T18:08:10.184741] LOG: [APP] Repeater CC already has pin in current batch, SNR will update on flush if better +[2026-02-20T18:08:10.184756] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=13.0, location=47.36345,-122.17707 +[2026-02-20T18:08:11.248986] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:08:12.603508] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:12.796135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bd 34 0b 00 00 00 86 23 00 00 +[2026-02-20T18:08:12.796291] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:12.796311] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:14.235747] LOG: [CONN] Frame received (110 bytes): 88 30 bb 15 37 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 20 20 20 20 75 68 26 07 f4 f1 fd 3e 0c 9f 7b fa 92 6e 6b ef fc 7a 08 24 07 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7e cc 91 bf 46 dd fc fa 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e +[2026-02-20T18:08:14.235831] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:14.235845] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:14.235876] LOG: [RX PARSE] RAW Packet (107 bytes): 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E +[2026-02-20T18:08:14.235883] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:14.235890] LOG: [RX PARSE] Path length offset: 1, Path length: 55 +[2026-02-20T18:08:14.235899] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=55, firstHop=0x7e, lastHop=0xcc, SNR=12.0, RSSI=-69, payload=50 bytes +[2026-02-20T18:08:14.235906] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=55 +[2026-02-20T18:08:14.235909] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:14.235913] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:14.235944] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:14.235949] LOG: [RX FILTER] Raw packet (107 bytes): 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E +[2026-02-20T18:08:14.235958] LOG: [RX FILTER] Header: 0x15 | PathLength: 55 | SNR: 12.0 +[2026-02-20T18:08:14.235965] LOG: [RX FILTER] ✓ RSSI OK (-69 < -30) +[2026-02-20T18:08:14.235968] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:14.235971] LOG: [RX FILTER] Channel hash: 0x91 +[2026-02-20T18:08:14.235978] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x91 +[2026-02-20T18:08:14.236016] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:08:14.236019] LOG: [RX LOG] Dropped packet hex: 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E +[2026-02-20T18:08:14.317657] LOG: [PING] RX listening window ended +[2026-02-20T18:08:14.317758] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:08:14.317787] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:08:14.317836] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:08:14.317844] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:08:14.317855] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:08:14.317871] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:08:14.317880] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:08:14.318224] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:08:16.307329] LOG: [CONN] Frame received (47 bytes): 88 31 bd 15 07 4e 1f 9c fb 23 7e cc ca 7d d6 66 66 c6 6b 4b 77 2e 74 a2 50 ea 56 39 7e 7c 2f 3c ed 79 5e e8 65 99 17 c2 28 f1 67 51 79 48 9b +[2026-02-20T18:08:16.307378] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:16.307421] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:16.307471] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 4E 1F 9C FB 23 7E CC CA 7D D6 66 66 C6 6B 4B 77 2E 74 A2 50 EA 56 39 7E 7C 2F 3C ED 79 5E E8 65 99 17 C2 28 F1 67 51 79 48 9B +[2026-02-20T18:08:16.307490] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:16.307502] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:08:16.307529] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x4e, lastHop=0xcc, SNR=12.25, RSSI=-67, payload=35 bytes +[2026-02-20T18:08:16.307544] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:08:16.307554] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:16.307570] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:16.307616] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:16.307628] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 4E 1F 9C FB 23 7E CC CA 7D D6 66 66 C6 6B 4B 77 2E 74 A2 50 EA 56 39 7E 7C 2F 3C ED 79 5E E8 65 99 17 C2 28 F1 67 51 79 48 9B +[2026-02-20T18:08:16.307650] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 +[2026-02-20T18:08:16.307664] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) +[2026-02-20T18:08:16.307679] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:16.307691] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:08:16.307703] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:08:16.307719] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:08:16.307731] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:08:16.307805] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:08:16.307976] LOG: [RX FILTER] Decrypted message (15 chars): "DieterPibbs1: P" +[2026-02-20T18:08:16.307999] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:08:16.308015] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:08:16.308156] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=7 +[2026-02-20T18:08:16.308169] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:16.308187] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=13.0, new=12.25 +[2026-02-20T18:08:16.308214] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:16.308232] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=13.0 +[2026-02-20T18:08:17.605077] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:17.715740] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bd 31 0b 00 00 00 86 23 00 00 +[2026-02-20T18:08:17.715865] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:17.715890] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:19.320347] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:08:19.320533] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:08:19.320549] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:08:19.771810] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:08:19.771879] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:08:19.771891] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771639999} +[2026-02-20T18:08:19.771909] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:08:19.771922] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:08:19.772257] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:08:19.772270] LOG: [APP] Upload success: +1 items (total: 39) +[2026-02-20T18:08:21.139015] LOG: [CONN] Frame received (140 bytes): 88 33 bf 15 04 01 e0 7e cc ca 18 f5 b6 4e 6b d6 15 ad 8d 9c b6 ad 0b 38 95 b5 98 11 0f bf fa df bb eb 0f 98 56 38 9c a7 76 04 81 8e c9 30 07 53 db ee 1d a2 b1 c4 9f 9b 46 a2 91 c4 c1 9f 02 66 e5 1c 7c d9 d5 ac 33 20 10 8a a1 52 f5 fa d0 55 38 e2 28 ae f5 7f 1f 29 aa 25 2d 6c eb 62 f6 aa 81 ac bd 36 6d 30 1b 69 f6 b8 79 cd 79 8d 0f c7 0b 15 14 ef d5 23 cd 08 50 1c 41 98 91 bd ad 5b c7 86 29 86 b9 94 ee ad ba 0a 11 ba +[2026-02-20T18:08:21.139435] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:21.139582] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:21.139748] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 01 E0 7E CC CA 18 F5 B6 4E 6B D6 15 AD 8D 9C B6 AD 0B 38 95 B5 98 11 0F BF FA DF BB EB 0F 98 56 38 9C A7 76 04 81 8E C9 30 07 53 DB EE 1D A2 B1 C4 9F 9B 46 A2 91 C4 C1 9F 02 66 E5 1C 7C D9 D5 AC 33 20 10 8A A1 52 F5 FA D0 55 38 E2 28 AE F5 7F 1F 29 AA 25 2D 6C EB 62 F6 AA 81 AC BD 36 6D 30 1B 69 F6 B8 79 CD 79 8D 0F C7 0B 15 14 EF D5 23 CD 08 50 1C 41 98 91 BD AD 5B C7 86 29 86 B9 94 EE AD BA 0A 11 BA +[2026-02-20T18:08:21.139775] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:21.139787] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:08:21.139824] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x01, lastHop=0xcc, SNR=12.75, RSSI=-65, payload=131 bytes +[2026-02-20T18:08:21.139838] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:08:21.139855] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:21.139866] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:21.139983] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:21.139995] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 01 E0 7E CC CA 18 F5 B6 4E 6B D6 15 AD 8D 9C B6 AD 0B 38 95 B5 98 11 0F BF FA DF BB EB 0F 98 56 38 9C A7 76 04 81 8E C9 30 07 53 DB EE 1D A2 B1 C4 9F 9B 46 A2 91 C4 C1 9F 02 66 E5 1C 7C D9 D5 AC 33 20 10 8A A1 52 F5 FA D0 55 38 E2 28 AE F5 7F 1F 29 AA 25 2D 6C EB 62 F6 AA 81 AC BD 36 6D 30 1B 69 F6 B8 79 CD 79 8D 0F C7 0B 15 14 EF D5 23 CD 08 50 1C 41 98 91 BD AD 5B C7 86 29 86 B9 94 EE AD BA 0A 11 BA +[2026-02-20T18:08:21.140022] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.75 +[2026-02-20T18:08:21.140037] LOG: [RX FILTER] ✓ RSSI OK (-65 < -30) +[2026-02-20T18:08:21.140062] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:21.140073] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:08:21.140086] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:08:21.140103] LOG: [RX FILTER] Encrypted message: 128 bytes +[2026-02-20T18:08:21.140114] LOG: [CRYPTO] Decrypting message (128 bytes) +[2026-02-20T18:08:21.140245] LOG: [CRYPTO] Decrypted successfully (128 bytes) +[2026-02-20T18:08:21.140442] LOG: [RX FILTER] Decrypted message (110 chars): "HowlBot: 4E: The Winchester Re... 1F: First Hill Skyline 53..." +[2026-02-20T18:08:21.140466] LOG: [RX FILTER] Printable ratio: 86.4% (threshold: 60.0%) +[2026-02-20T18:08:21.140481] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:08:21.140514] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.75, path_length=4 +[2026-02-20T18:08:21.140525] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:21.140541] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=13.0, new=12.75 +[2026-02-20T18:08:21.140567] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:21.140586] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.75, current_best=13.0 +[2026-02-20T18:08:22.573650] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:08:22.573697] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:08:22.602627] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:22.692285] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bf 33 0b 00 00 00 87 23 00 00 +[2026-02-20T18:08:22.692344] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:22.692352] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:24.772786] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:08:27.603185] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:08:27.603308] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:27.703994] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:08:27.704092] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:08:27.704104] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:08:27.704119] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:08:27.762754] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bf 33 0b 00 00 00 87 23 00 00 +[2026-02-20T18:08:27.762917] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:27.762933] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:29.148233] LOG: [RX BATCH] 30s timeout triggered for repeater CC +[2026-02-20T18:08:29.148348] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:08:29.148359] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:08:29.148383] LOG: [RX BATCH] Posting repeater CC: snr=13.0, location=47.36345,-122.17707 +[2026-02-20T18:08:29.148392] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:08:29.148401] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=13.0, location=47.36345,-122.17707 +[2026-02-20T18:08:29.148417] LOG: [APP] Updated RX pin SNR for repeater=CC: 12.50 -> 13.00 +[2026-02-20T18:08:29.148426] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:08:29.148434] LOG: [APP] Added RX log entry: repeater=CC, snr=13.0, pathLen=12 +[2026-02-20T18:08:29.148527] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:08:31.010685] LOG: [CONN] Frame received (91 bytes): 88 32 be 15 03 c7 32 cc 81 05 3e 17 35 0d 38 ba b2 08 18 0d 27 2a 27 78 a6 ca 83 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb ee 9b 6c cd b2 47 a4 4f 16 93 41 e4 3c 59 25 af c1 be 63 10 2e 56 5c 90 59 11 86 e3 ed 70 13 49 +[2026-02-20T18:08:31.010838] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:31.010873] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:31.010955] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 C7 32 CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB EE 9B 6C CD B2 47 A4 4F 16 93 41 E4 3C 59 25 AF C1 BE 63 10 2E 56 5C 90 59 11 86 E3 ED 70 13 49 +[2026-02-20T18:08:31.010978] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:31.010989] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:08:31.011016] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xc7, lastHop=0xcc, SNR=12.5, RSSI=-66, payload=83 bytes +[2026-02-20T18:08:31.011032] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:08:31.011047] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:31.011059] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:31.011135] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:31.011151] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 C7 32 CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB EE 9B 6C CD B2 47 A4 4F 16 93 41 E4 3C 59 25 AF C1 BE 63 10 2E 56 5C 90 59 11 86 E3 ED 70 13 49 +[2026-02-20T18:08:31.011171] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 12.5 +[2026-02-20T18:08:31.011198] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) +[2026-02-20T18:08:31.011209] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:31.011219] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:08:31.011236] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:08:31.011248] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:08:31.011264] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:08:31.011364] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:08:31.011536] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.39640, -122.51882 [..." +[2026-02-20T18:08:31.011561] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:08:31.011576] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:08:31.011609] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=3 +[2026-02-20T18:08:31.011620] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:31.011637] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 +[2026-02-20T18:08:31.011659] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:08:31.011678] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:31.011703] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:08:31.011722] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:08:31.011746] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36345,-122.17707 (batch tracking: 1 repeaters, rxCount: 27) +[2026-02-20T18:08:31.011766] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:08:31.011790] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:08:31.012313] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:08:31.012327] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:08:31.012343] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:08:32.603251] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:32.714230] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 32 0b 00 00 00 87 23 00 00 +[2026-02-20T18:08:32.714392] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:32.714409] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:34.787712] LOG: [CONN] Frame received (44 bytes): 88 31 bd 15 04 41 32 9b cc ca 3a a8 5d ca 70 2f f8 c7 2a f9 17 c2 93 a5 03 91 d6 6c b3 75 70 b8 b8 82 de e7 68 f3 23 23 14 1b 2b be +[2026-02-20T18:08:34.787824] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:34.787845] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:34.787900] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 41 32 9B CC CA 3A A8 5D CA 70 2F F8 C7 2A F9 17 C2 93 A5 03 91 D6 6C B3 75 70 B8 B8 82 DE E7 68 F3 23 23 14 1B 2B BE +[2026-02-20T18:08:34.787909] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:34.787916] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:08:34.787936] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x41, lastHop=0xcc, SNR=12.25, RSSI=-67, payload=35 bytes +[2026-02-20T18:08:34.787944] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:08:34.787954] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:34.787961] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:34.787989] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:34.787998] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 41 32 9B CC CA 3A A8 5D CA 70 2F F8 C7 2A F9 17 C2 93 A5 03 91 D6 6C B3 75 70 B8 B8 82 DE E7 68 F3 23 23 14 1B 2B BE +[2026-02-20T18:08:34.788008] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.25 +[2026-02-20T18:08:34.788018] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) +[2026-02-20T18:08:34.788029] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:34.788036] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:08:34.788047] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:08:34.788054] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:08:34.788061] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:08:34.788106] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:08:34.788234] LOG: [RX FILTER] Decrypted message (13 chars): "Airhack: Path" +[2026-02-20T18:08:34.788251] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:08:34.788262] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:08:34.788283] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=4 +[2026-02-20T18:08:34.788290] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:08:34.788301] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.5, new=12.25 +[2026-02-20T18:08:34.788320] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:08:34.788332] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=12.5 +[2026-02-20T18:08:36.780132] LOG: [GPS SERVICE] Position stream fired: lat=47.36336, lon=-122.17682, accuracy=3.8m +[2026-02-20T18:08:36.780178] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:08:36.780198] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:08:36.780207] LOG: [RX BATCH] Distance check for repeater CC: 21.78m from first observation (threshold=25m) +[2026-02-20T18:08:36.780251] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:08:37.573839] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:08:37.574084] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:08:37.574097] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:08:37.575482] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:08:37.602891] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:37.693088] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff bd 31 0b 00 00 00 87 23 00 00 +[2026-02-20T18:08:37.693213] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:37.693239] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:08:38.047340] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:08:38.047432] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:08:38.047455] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640017} +[2026-02-20T18:08:38.047474] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:08:38.047493] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:08:38.047916] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:08:38.047934] LOG: [APP] Upload success: +1 items (total: 40) +[2026-02-20T18:08:40.635793] LOG: [CONN] Frame received (49 bytes): 88 30 c5 15 0b c7 7e 75 20 20 20 20 53 7e 9d cc 81 05 3e 17 35 0d 38 ba b2 08 18 0d 27 2a 27 78 a6 ca 83 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df +[2026-02-20T18:08:40.636002] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:40.636039] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:40.636103] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF +[2026-02-20T18:08:40.636118] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:40.636129] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:08:40.636173] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=33 bytes +[2026-02-20T18:08:40.636187] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:08:40.636203] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:40.636213] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:40.636260] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:08:40.636278] LOG: [RX FILTER] Raw packet (46 bytes): 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF +[2026-02-20T18:08:40.636294] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.0 +[2026-02-20T18:08:40.636314] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:08:40.636326] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:08:40.636336] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:08:40.636352] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:08:40.636365] LOG: [RX FILTER] Encrypted message: 30 bytes +[2026-02-20T18:08:40.636375] LOG: [CRYPTO] Decrypting message (30 bytes) +[2026-02-20T18:08:40.636558] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:08:40.636609] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:08:40.636847] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:08:40.636941] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:08:40.636966] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF +[2026-02-20T18:08:41.766274] LOG: [GPS SERVICE] Position stream fired: lat=47.36303, lon=-122.17596, accuracy=10.1m +[2026-02-20T18:08:41.766322] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:08:41.766334] LOG: [RX BATCH] Distance check for repeater CC: 96.40m from first observation (threshold=25m) +[2026-02-20T18:08:41.766339] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:08:41.766341] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:08:41.766349] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:08:41.766354] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:08:41.766357] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:08:41.766380] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36345,-122.17707 +[2026-02-20T18:08:41.766385] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 +[2026-02-20T18:08:41.766391] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:08:41.766395] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=3 +[2026-02-20T18:08:41.766451] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:08:41.766456] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:08:42.602799] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:42.644762] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 0b 00 00 00 87 23 00 00 +[2026-02-20T18:08:42.644888] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:42.644904] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:43.049159] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:08:44.318975] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:08:44.319035] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:08:44.319042] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:08:44.319058] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:08:44.319073] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36303, -122.17596 [0.3w]" +[2026-02-20T18:08:44.319077] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:08:44.319081] LOG: [TX LOG] Payload: "@[MapperBot] 47.36303, -122.17596 [0.3w]" +[2026-02-20T18:08:44.319085] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:08:44.319088] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:08:44.319094] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:08:44.319096] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:08:44.319104] LOG: [CONN] Sending ping: @[MapperBot] 47.36303, -122.17596 [0.3w] +[2026-02-20T18:08:44.504072] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:08:44.504156] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:08:44.504166] LOG: [CONN] Received OK response +[2026-02-20T18:08:46.220704] LOG: [CONN] Frame received (73 bytes): 88 30 c3 15 01 cc 81 b9 c8 1c 26 12 b6 21 4b 75 33 29 42 28 28 b4 ae d2 3e 6d 72 46 cb 1c 13 83 2f 13 04 3d 8c 85 71 17 26 4e f5 41 2a 3a f0 4f ca 28 c7 82 b4 e9 9e 8d ce 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:08:46.220872] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:08:46.220903] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:08:46.220983] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 B9 C8 1C 26 12 B6 21 4B 75 33 29 42 28 28 B4 AE D2 3E 6D 72 46 CB 1C 13 83 2F 13 04 3D 8C 85 71 17 26 4E F5 41 2A 3A F0 4F CA 28 C7 82 B4 E9 9E 8D CE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:08:46.221004] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:08:46.221016] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:08:46.221045] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-61, payload=67 bytes +[2026-02-20T18:08:46.221059] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:08:46.221070] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:08:46.221087] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-61 +[2026-02-20T18:08:46.221099] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:08:46.221109] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:08:46.221129] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:08:46.221139] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:08:46.221153] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:08:46.753693] LOG: [GPS SERVICE] Position stream fired: lat=47.36273, lon=-122.17506, accuracy=3.8m +[2026-02-20T18:08:47.505017] LOG: [PING] Ping sent successfully +[2026-02-20T18:08:47.603957] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:47.770791] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:08:47.770853] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:47.770861] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:49.320737] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:08:51.764756] LOG: [GPS SERVICE] Position stream fired: lat=47.36233, lon=-122.17416, accuracy=3.8m +[2026-02-20T18:08:52.505872] LOG: [PING] RX listening window ended +[2026-02-20T18:08:52.506052] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:08:52.506080] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:08:52.506153] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:08:52.506168] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:08:52.506179] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:08:52.506203] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:08:52.506218] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:08:52.506610] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:08:52.573676] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:08:52.573855] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:08:52.573868] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:08:52.573882] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:08:52.577682] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:08:52.602801] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:52.783877] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:08:52.783949] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:52.783957] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:08:53.084037] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:08:53.084088] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:08:53.084097] LOG: [API] Response (200) in 0.51s: {"success":true,"expires_at":1771640032} +[2026-02-20T18:08:53.084106] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:08:53.084118] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:08:53.084848] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:08:53.084869] LOG: [APP] Upload success: +2 items (total: 42) +[2026-02-20T18:08:56.761688] LOG: [GPS SERVICE] Position stream fired: lat=47.36188, lon=-122.17324, accuracy=3.8m +[2026-02-20T18:08:57.508870] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:08:57.509085] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:08:57.604396] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:08:57.604583] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:08:57.794343] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:08:57.794465] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:08:57.794475] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:08:57.794495] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:08:57.855567] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:08:57.855702] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:08:57.855730] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:08:58.087297] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:09:01.784072] LOG: [GPS SERVICE] Position stream fired: lat=47.36128, lon=-122.17240, accuracy=3.8m +[2026-02-20T18:09:02.603025] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:02.712965] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:09:02.713026] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:02.713037] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:06.772021] LOG: [GPS SERVICE] Position stream fired: lat=47.36065, lon=-122.17161, accuracy=3.8m +[2026-02-20T18:09:07.580453] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:09:07.580610] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:09:07.603300] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:07.725309] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:09:07.725439] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:07.725465] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:11.753460] LOG: [GPS SERVICE] Position stream fired: lat=47.35995, lon=-122.17090, accuracy=3.8m +[2026-02-20T18:09:11.753514] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:09:11.753586] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:09:12.602908] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:12.735058] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:09:12.735116] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:12.735123] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:09:16.771635] LOG: [GPS SERVICE] Position stream fired: lat=47.35934, lon=-122.17006, accuracy=3.8m +[2026-02-20T18:09:17.603932] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:17.745385] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:09:17.745490] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:17.745510] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:21.764729] LOG: [GPS SERVICE] Position stream fired: lat=47.35889, lon=-122.16921, accuracy=3.8m +[2026-02-20T18:09:22.507198] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:09:22.511382] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:09:22.511529] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:09:22.511693] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:09:22.511834] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35889, -122.16921 [0.3w]" +[2026-02-20T18:09:22.511842] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:09:22.511858] LOG: [TX LOG] Payload: "@[MapperBot] 47.35889, -122.16921 [0.3w]" +[2026-02-20T18:09:22.511870] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:09:22.511914] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:09:22.511924] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:09:22.511926] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:09:22.511970] LOG: [CONN] Sending ping: @[MapperBot] 47.35889, -122.16921 [0.3w] +[2026-02-20T18:09:22.573948] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:09:22.574126] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:09:22.604848] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:22.639756] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:09:22.639872] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:09:22.639886] LOG: [CONN] Received OK response +[2026-02-20T18:09:22.691794] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 +[2026-02-20T18:09:22.691901] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:22.691917] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:23.207092] LOG: [CONN] Frame received (73 bytes): 88 31 c7 15 01 cc 81 00 65 30 16 44 58 60 e5 b1 6f ee 35 96 a3 49 6c 43 04 84 e6 4d 5e e9 25 12 5a a1 b7 f3 53 fc 00 09 13 36 18 09 a2 55 35 78 b1 14 51 5c 33 c1 f5 27 69 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:09:23.207221] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:09:23.207246] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:09:23.207301] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 00 65 30 16 44 58 60 E5 B1 6F EE 35 96 A3 49 6C 43 04 84 E6 4D 5E E9 25 12 5A A1 B7 F3 53 FC 00 09 13 36 18 09 A2 55 35 78 B1 14 51 5C 33 C1 F5 27 69 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:09:23.207316] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:09:23.207326] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:09:23.207350] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=67 bytes +[2026-02-20T18:09:23.207365] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:09:23.207372] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:09:23.207391] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 +[2026-02-20T18:09:23.207399] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:09:23.207407] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:09:23.207425] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:09:23.207433] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:09:23.207440] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:09:25.640368] LOG: [PING] Ping sent successfully +[2026-02-20T18:09:26.775778] LOG: [GPS SERVICE] Position stream fired: lat=47.35850, lon=-122.16826, accuracy=3.8m +[2026-02-20T18:09:27.515727] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:09:27.603162] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:09:27.603419] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:27.762959] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:09:27.763102] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:09:27.763121] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:09:27.763137] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:09:27.822483] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:27.822622] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:27.822639] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:30.641012] LOG: [PING] RX listening window ended +[2026-02-20T18:09:30.641216] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:09:30.641271] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:09:30.641368] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:09:30.641382] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:09:30.641401] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:09:30.641427] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:09:30.641443] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:09:30.660793] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:09:31.768739] LOG: [GPS SERVICE] Position stream fired: lat=47.35824, lon=-122.16740, accuracy=3.8m +[2026-02-20T18:09:32.602705] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:32.683925] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:32.684011] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:32.684023] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:35.661613] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:09:35.661701] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:09:35.661705] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:09:36.280947] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:09:36.280989] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:09:36.281008] LOG: [API] Response (200) in 0.62s: {"success":true,"expires_at":1771640076} +[2026-02-20T18:09:36.281028] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:09:36.281048] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:09:36.281910] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:09:36.281928] LOG: [APP] Upload success: +1 items (total: 43) +[2026-02-20T18:09:36.759853] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.16658, accuracy=3.8m +[2026-02-20T18:09:37.573894] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:09:37.574089] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:09:37.602829] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:37.694955] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:37.695109] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:37.695129] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:41.282955] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:09:41.778481] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.16609, accuracy=3.8m +[2026-02-20T18:09:41.778564] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:09:41.778584] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:09:42.603270] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:42.705300] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:42.705453] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:42.705473] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:47.605687] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:47.684226] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:47.684350] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:47.684369] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:52.573703] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:09:52.573776] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:09:52.603026] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:52.694636] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:52.694704] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:52.694715] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:09:57.602963] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:09:57.603166] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:09:57.735611] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:09:57.735737] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:09:57.735750] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:09:57.735768] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T18:09:57.793304] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:09:57.793485] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:09:57.793506] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:00.641669] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:10:00.641746] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:10:00.641757] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:10:00.641779] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:10:00.641800] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35803, -122.16609 [0.3w]" +[2026-02-20T18:10:00.641806] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:10:00.641810] LOG: [TX LOG] Payload: "@[MapperBot] 47.35803, -122.16609 [0.3w]" +[2026-02-20T18:10:00.641818] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:10:00.641822] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:10:00.641828] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:10:00.641834] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:10:00.641843] LOG: [CONN] Sending ping: @[MapperBot] 47.35803, -122.16609 [0.3w] +[2026-02-20T18:10:00.708993] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:10:00.709118] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:10:00.709132] LOG: [CONN] Received OK response +[2026-02-20T18:10:02.296256] LOG: [CONN] Frame received (73 bytes): 88 30 ce 15 01 cc 81 70 3e ed 82 c0 21 7e 14 da d3 8a e4 84 f6 f5 88 c1 17 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 9c 1c f5 18 f6 36 d2 69 b9 ae 92 be f8 43 96 bc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:10:02.296289] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:10:02.296312] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:10:02.296344] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 70 3E ED 82 C0 21 7E 14 DA D3 8A E4 84 F6 F5 88 C1 17 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 9C 1C F5 18 F6 36 D2 69 B9 AE 92 BE F8 43 96 BC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:10:02.296351] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:10:02.296358] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:10:02.296375] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-50, payload=67 bytes +[2026-02-20T18:10:02.296384] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:10:02.296390] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:10:02.296395] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-50 +[2026-02-20T18:10:02.296402] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:10:02.296407] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:10:02.296467] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:10:02.296472] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:10:02.296476] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:10:02.603842] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:02.651931] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:02.652009] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:02.652019] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:03.710945] LOG: [PING] Ping sent successfully +[2026-02-20T18:10:05.642595] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:10:06.766296] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.16579, accuracy=3.8m +[2026-02-20T18:10:07.573818] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:10:07.573968] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:10:07.603739] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:07.665080] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:07.665209] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:07.665235] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:08.711599] LOG: [PING] RX listening window ended +[2026-02-20T18:10:08.711658] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:10:08.711667] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:10:08.711697] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:10:08.711701] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:10:08.711705] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:10:08.711713] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:10:08.711717] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:10:08.712011] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:10:11.763251] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.16503, accuracy=16.6m +[2026-02-20T18:10:12.603095] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:12.674228] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:12.674336] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:12.674351] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:13.713852] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:10:13.714075] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:10:13.714094] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:10:14.253600] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:10:14.253641] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:10:14.253650] LOG: [API] Response (200) in 0.54s: {"success":true,"expires_at":1771640114} +[2026-02-20T18:10:14.253657] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:10:14.253668] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:10:14.253887] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:10:14.253895] LOG: [APP] Upload success: +1 items (total: 44) +[2026-02-20T18:10:16.020365] LOG: [CONN] Frame received (49 bytes): 88 31 cb 15 0a 7e 75 a6 20 20 53 a5 e8 9d cc ba 48 dd 91 cb 6a 46 d5 ec 39 eb 72 d4 5d 1b 3b 3f c0 8b e5 31 aa d6 53 b9 fe ea a8 64 d8 fd 8e c5 f9 +[2026-02-20T18:10:16.020522] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:10:16.020553] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:10:16.020620] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 +[2026-02-20T18:10:16.020635] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:10:16.020652] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:10:16.020676] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-53, payload=34 bytes +[2026-02-20T18:10:16.020690] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:10:16.020705] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:10:16.020715] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:10:16.020761] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:10:16.020778] LOG: [RX FILTER] Raw packet (46 bytes): 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 +[2026-02-20T18:10:16.020794] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 +[2026-02-20T18:10:16.020813] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) +[2026-02-20T18:10:16.020825] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:10:16.020835] LOG: [RX FILTER] Channel hash: 0xba +[2026-02-20T18:10:16.020852] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba +[2026-02-20T18:10:16.020909] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:10:16.020925] LOG: [RX LOG] Dropped packet hex: 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 +[2026-02-20T18:10:16.795798] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.16397, accuracy=3.8m +[2026-02-20T18:10:16.795838] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:10:16.795894] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:10:17.603254] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:17.713546] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:17.713672] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:17.713697] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:19.258979] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:10:21.790433] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.16277, accuracy=3.8m +[2026-02-20T18:10:22.574099] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:10:22.574265] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:10:22.603736] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:22.753516] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:22.753651] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:22.753670] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:27.100807] LOG: [GPS SERVICE] Position stream fired: lat=47.35792, lon=-122.16141, accuracy=3.8m +[2026-02-20T18:10:27.605284] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:10:27.605427] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:27.762158] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:10:27.762238] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:10:27.762251] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:10:27.762260] LOG: [CONN] Battery updated: 4059mV (88%) +[2026-02-20T18:10:27.823542] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cb 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:27.823689] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:27.823713] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:10:31.799520] LOG: [GPS SERVICE] Position stream fired: lat=47.35793, lon=-122.16014, accuracy=3.8m +[2026-02-20T18:10:32.602874] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:32.684220] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:32.684345] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:32.684370] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:36.765414] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.15879, accuracy=3.8m +[2026-02-20T18:10:37.573611] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:10:37.573677] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:10:37.602612] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:37.692701] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 +[2026-02-20T18:10:37.692754] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:37.692760] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:38.712957] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:10:38.713073] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:10:38.713083] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:10:38.713120] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:10:38.713147] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35795, -122.15879 [0.3w]" +[2026-02-20T18:10:38.713156] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:10:38.713160] LOG: [TX LOG] Payload: "@[MapperBot] 47.35795, -122.15879 [0.3w]" +[2026-02-20T18:10:38.713168] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:10:38.713177] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:10:38.713183] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:10:38.713188] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:10:38.713204] LOG: [CONN] Sending ping: @[MapperBot] 47.35795, -122.15879 [0.3w] +[2026-02-20T18:10:38.805507] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:10:38.805606] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:10:38.805621] LOG: [CONN] Received OK response +[2026-02-20T18:10:39.798987] LOG: [CONN] Frame received (73 bytes): 88 30 c4 15 01 cc 81 77 e9 2f 36 cf bd b7 2d 93 fb b0 81 39 1e 26 f8 1c 0e 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 5f 02 18 04 40 35 c7 8e 58 3e f2 ec 49 03 ca 3e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:10:39.799128] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:10:39.799157] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:10:39.799214] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 77 E9 2F 36 CF BD B7 2D 93 FB B0 81 39 1E 26 F8 1C 0E 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 5F 02 18 04 40 35 C7 8E 58 3E F2 EC 49 03 CA 3E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:10:39.799237] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:10:39.799245] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:10:39.799263] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes +[2026-02-20T18:10:39.799279] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:10:39.799556] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:10:39.799571] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-60 +[2026-02-20T18:10:39.799581] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:10:39.799589] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:10:39.799603] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:10:39.799610] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:10:39.799617] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:10:40.289127] LOG: [CONN] Frame received (44 bytes): 88 2e c4 15 04 ba 43 86 cc d9 5a 3b c9 49 08 78 94 b6 31 21 1e c8 3c bb 95 c1 49 36 e5 67 7d 32 6a 4f b7 dd 0e b4 c6 84 6a 19 12 b5 +[2026-02-20T18:10:40.289253] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:10:40.289277] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:10:40.289323] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 +[2026-02-20T18:10:40.289332] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:10:40.289341] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:10:40.289362] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xba, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=35 bytes +[2026-02-20T18:10:40.289373] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:10:40.289380] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:10:40.289387] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-60 +[2026-02-20T18:10:40.289395] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:10:40.289404] LOG: [TX LOG] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:10:40.289411] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xd9, expected=0x81 +[2026-02-20T18:10:40.289425] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:10:40.289433] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:10:40.289438] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:10:40.289467] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:10:40.289475] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 +[2026-02-20T18:10:40.289485] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 +[2026-02-20T18:10:40.289497] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:10:40.289505] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:10:40.289511] LOG: [RX FILTER] Channel hash: 0xd9 +[2026-02-20T18:10:40.289522] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xd9 +[2026-02-20T18:10:40.289554] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:10:40.289564] LOG: [RX LOG] Dropped packet hex: 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 +[2026-02-20T18:10:41.768572] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.15743, accuracy=3.8m +[2026-02-20T18:10:41.805696] LOG: [PING] Ping sent successfully +[2026-02-20T18:10:42.602671] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:42.732320] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:10:42.732372] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:42.732378] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:10:43.713593] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:10:46.788265] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15609, accuracy=4.0m +[2026-02-20T18:10:46.806744] LOG: [PING] RX listening window ended +[2026-02-20T18:10:46.806858] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:10:46.806895] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:10:46.806957] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:10:46.806965] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:10:46.806977] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:10:46.807028] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:10:46.807038] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:10:46.818563] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:10:47.604447] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:47.742509] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:10:47.742599] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:47.742605] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:51.781100] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15471, accuracy=4.1m +[2026-02-20T18:10:51.781156] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:10:51.781235] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:10:51.821920] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:10:51.821989] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:10:51.821993] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:10:52.464149] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:10:52.464207] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:10:52.464214] LOG: [API] Response (200) in 0.64s: {"success":true,"expires_at":1771640152} +[2026-02-20T18:10:52.464225] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:10:52.464235] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:10:52.464933] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:10:52.464947] LOG: [APP] Upload success: +1 items (total: 45) +[2026-02-20T18:10:52.573918] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:10:52.574073] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:10:52.604328] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:52.755510] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:10:52.755669] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:52.755696] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:10:56.789783] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15333, accuracy=3.8m +[2026-02-20T18:10:57.465857] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:10:57.602750] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:10:57.602833] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:10:57.761973] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:10:57.762005] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:10:57.762013] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:10:57.762019] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:10:57.822762] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:10:57.822813] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:10:57.822820] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:01.761072] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.15199, accuracy=3.8m +[2026-02-20T18:11:02.603259] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:02.711303] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:11:02.711358] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:02.711363] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:11:06.753474] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.15103, accuracy=3.8m +[2026-02-20T18:11:07.575905] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:11:07.576067] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:11:07.603152] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:07.722333] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:11:07.722417] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:07.722432] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:11:11.786411] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.15012, accuracy=3.8m +[2026-02-20T18:11:12.602925] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:12.732751] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:11:12.732905] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:12.732924] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:16.782083] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14910, accuracy=3.8m +[2026-02-20T18:11:16.807679] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:11:16.807798] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:11:16.807809] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:11:16.807839] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:11:16.807867] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35796, -122.14910 [0.3w]" +[2026-02-20T18:11:16.807879] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:11:16.807884] LOG: [TX LOG] Payload: "@[MapperBot] 47.35796, -122.14910 [0.3w]" +[2026-02-20T18:11:16.807892] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:11:16.807905] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:11:16.807912] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:11:16.807918] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:11:16.807934] LOG: [CONN] Sending ping: @[MapperBot] 47.35796, -122.14910 [0.3w] +[2026-02-20T18:11:17.022894] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:11:17.023041] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:11:17.023056] LOG: [CONN] Received OK response +[2026-02-20T18:11:17.604221] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:17.683112] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 +[2026-02-20T18:11:17.683236] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:17.683255] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:18.765455] LOG: [CONN] Frame received (73 bytes): 88 2f c3 15 01 cc 81 7e 8e 32 03 86 48 7d 53 35 9a e1 9b 4f ed 26 21 6f 6a 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 b6 a4 30 34 b4 c2 37 bc b1 e2 5d 46 bf 94 a3 85 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:11:18.765626] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:11:18.765639] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:11:18.765666] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 7E 8E 32 03 86 48 7D 53 35 9A E1 9B 4F ED 26 21 6F 6A 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 B6 A4 30 34 B4 C2 37 BC B1 E2 5D 46 BF 94 A3 85 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:11:18.765674] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:11:18.765678] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:11:18.765693] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=67 bytes +[2026-02-20T18:11:18.765699] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:11:18.765702] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:11:18.765709] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-61 +[2026-02-20T18:11:18.765712] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:11:18.765716] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:11:18.765723] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:11:18.765726] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:11:18.765730] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:11:19.992959] LOG: [PING] Ping sent successfully +[2026-02-20T18:11:21.243862] LOG: [CONN] Frame received (55 bytes): 88 2f c2 15 21 75 b0 0a ab 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0a ab 7e db cc ba 13 7e e4 b3 61 3d 2e 96 3d 5a 80 8f 8c c0 27 21 +[2026-02-20T18:11:21.244017] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:11:21.244048] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:11:21.244105] LOG: [RX PARSE] RAW Packet (52 bytes): 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 +[2026-02-20T18:11:21.244126] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:11:21.244137] LOG: [RX PARSE] Path length offset: 1, Path length: 33 +[2026-02-20T18:11:21.244164] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0x75, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=17 bytes +[2026-02-20T18:11:21.244178] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 +[2026-02-20T18:11:21.244193] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:11:21.244208] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-62 +[2026-02-20T18:11:21.244218] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:11:21.244237] LOG: [TX LOG] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:11:21.244249] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xba, expected=0x81 +[2026-02-20T18:11:21.244260] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:11:21.244275] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:11:21.244285] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:11:21.244337] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:11:21.244353] LOG: [RX FILTER] Raw packet (52 bytes): 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 +[2026-02-20T18:11:21.244369] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 11.75 +[2026-02-20T18:11:21.244386] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:11:21.244397] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:11:21.244407] LOG: [RX FILTER] Channel hash: 0xba +[2026-02-20T18:11:21.244424] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba +[2026-02-20T18:11:21.244497] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:11:21.244509] LOG: [RX LOG] Dropped packet hex: 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 +[2026-02-20T18:11:21.768475] LOG: [CONN] Frame received (54 bytes): 88 31 c4 15 22 75 b0 0a ab 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 a5 c7 32 db cc ba 13 7e e4 b3 61 3d 2e 96 3d 5a 80 8f 8c c0 +[2026-02-20T18:11:21.768521] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:11:21.768551] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:11:21.768596] LOG: [RX PARSE] RAW Packet (51 bytes): 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 +[2026-02-20T18:11:21.768607] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:11:21.768621] LOG: [RX PARSE] Path length offset: 1, Path length: 34 +[2026-02-20T18:11:21.768645] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=34, firstHop=0x75, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=15 bytes +[2026-02-20T18:11:21.768659] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=34 +[2026-02-20T18:11:21.768668] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:11:21.768676] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-60 +[2026-02-20T18:11:21.768688] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:11:21.768699] LOG: [TX LOG] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:11:21.768707] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xba, expected=0x81 +[2026-02-20T18:11:21.768719] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:11:21.768814] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:11:21.768828] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:11:21.768869] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:11:21.768877] LOG: [RX FILTER] Raw packet (51 bytes): 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 +[2026-02-20T18:11:21.768892] LOG: [RX FILTER] Header: 0x15 | PathLength: 34 | SNR: 12.25 +[2026-02-20T18:11:21.768901] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:11:21.768912] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:11:21.768920] LOG: [RX FILTER] Channel hash: 0xba +[2026-02-20T18:11:21.768928] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba +[2026-02-20T18:11:21.768983] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:11:21.768995] LOG: [RX LOG] Dropped packet hex: 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 +[2026-02-20T18:11:21.791918] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.14803, accuracy=3.8m +[2026-02-20T18:11:21.791980] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:11:21.792002] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:11:21.808676] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:11:22.573785] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:11:22.573979] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:11:22.603353] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:22.724317] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c4 31 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:22.724423] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:22.724437] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:11:24.995128] LOG: [PING] RX listening window ended +[2026-02-20T18:11:24.995313] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:11:24.995335] LOG: [GRAPH] Recorded txFail event at -120dBm +[2026-02-20T18:11:24.995431] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:11:24.995485] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:11:24.995495] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:11:24.995518] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:11:24.995531] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:11:24.996271] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:11:26.778793] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14688, accuracy=3.8m +[2026-02-20T18:11:27.602870] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:11:27.603127] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:27.735121] LOG: [CONN] Frame received (11 bytes): 0c fb 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:11:27.735242] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:11:27.735277] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:11:27.735292] LOG: [CONN] Battery updated: 4091mV (91%) +[2026-02-20T18:11:27.793427] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:27.793559] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:27.793580] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:29.996730] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:11:29.996894] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:11:29.996906] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:11:30.698981] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:11:30.699086] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:11:30.699105] LOG: [API] Response (200) in 0.70s: {"success":true,"expires_at":1771640190} +[2026-02-20T18:11:30.699129] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:11:30.699147] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:11:30.700267] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:11:30.700298] LOG: [APP] Upload success: +1 items (total: 46) +[2026-02-20T18:11:31.797432] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.14562, accuracy=3.8m +[2026-02-20T18:11:32.602869] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:32.654063] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:32.654204] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:32.654225] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:34.186087] LOG: [CONN] Frame received (30 bytes): 88 2f c3 05 05 61 fa c7 7e cc 02 9c 75 91 bb d8 93 f5 cd f5 e2 8f 8e d2 4f 83 b6 07 f9 2b +[2026-02-20T18:11:34.186237] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:11:34.186301] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:11:34.186343] LOG: [RX PARSE] RAW Packet (27 bytes): 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B +[2026-02-20T18:11:34.186356] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T18:11:34.186367] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:11:34.186394] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=5, firstHop=0x61, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=20 bytes +[2026-02-20T18:11:34.186407] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=5 +[2026-02-20T18:11:34.186421] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:11:34.186433] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:11:34.186574] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:11:34.186588] LOG: [RX FILTER] Raw packet (27 bytes): 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B +[2026-02-20T18:11:34.186606] LOG: [RX FILTER] Header: 0x05 | PathLength: 5 | SNR: 11.75 +[2026-02-20T18:11:34.186621] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:11:34.186633] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) +[2026-02-20T18:11:34.186683] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:11:34.186694] LOG: [RX LOG] Dropped packet hex: 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B +[2026-02-20T18:11:35.700688] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:11:36.788827] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14439, accuracy=3.8m +[2026-02-20T18:11:37.573651] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:11:37.573736] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:11:37.602615] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:37.690899] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:37.690954] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:37.690962] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:41.761891] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14320, accuracy=3.8m +[2026-02-20T18:11:42.605468] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:42.705516] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:42.705636] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:42.705663] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:47.095614] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14189, accuracy=3.8m +[2026-02-20T18:11:47.603220] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:47.743499] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:47.743636] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:47.743652] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:51.792426] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14094, accuracy=3.8m +[2026-02-20T18:11:51.792474] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:11:51.792547] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:11:52.575321] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:11:52.575463] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:11:52.602873] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:52.753094] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 2f 0c 00 00 00 8a 23 00 00 +[2026-02-20T18:11:52.753231] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:52.753252] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:11:54.996573] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:11:54.996656] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:11:54.996667] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:11:54.996688] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:11:54.996710] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35796, -122.14094 [0.3w]" +[2026-02-20T18:11:54.996716] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:11:54.996720] LOG: [TX LOG] Payload: "@[MapperBot] 47.35796, -122.14094 [0.3w]" +[2026-02-20T18:11:54.996725] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:11:54.996730] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:11:54.996736] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:11:54.996741] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:11:54.996749] LOG: [CONN] Sending ping: @[MapperBot] 47.35796, -122.14094 [0.3w] +[2026-02-20T18:11:55.066169] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:11:55.066293] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:11:55.066312] LOG: [CONN] Received OK response +[2026-02-20T18:11:56.550183] LOG: [CONN] Frame received (73 bytes): 88 31 c3 15 01 cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:11:56.550232] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:11:56.550266] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:11:56.550309] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:11:56.550320] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:11:56.550330] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:11:56.550348] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=67 bytes +[2026-02-20T18:11:56.550360] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:11:56.550369] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:11:56.550376] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 +[2026-02-20T18:11:56.550386] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:11:56.550394] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:11:56.550488] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:11:56.550495] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:11:56.550502] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:11:56.756571] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14027, accuracy=3.8m +[2026-02-20T18:11:57.603629] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:11:57.603863] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:11:57.795884] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:11:57.796029] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:11:57.796048] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:11:57.796070] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:11:57.852784] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0d 00 00 00 8a 23 00 00 +[2026-02-20T18:11:57.852870] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:11:57.852879] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:11:58.069424] LOG: [PING] Ping sent successfully +[2026-02-20T18:12:00.000435] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:12:01.767319] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.13949, accuracy=3.8m +[2026-02-20T18:12:02.605217] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:02.714198] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0d 00 00 00 8a 23 00 00 +[2026-02-20T18:12:02.714284] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:02.714296] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:12:03.071116] LOG: [PING] RX listening window ended +[2026-02-20T18:12:03.071274] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:12:03.071303] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:12:03.071386] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:12:03.071404] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:12:03.071417] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:12:03.071443] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:12:03.071465] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:12:03.071873] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:12:06.760376] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13861, accuracy=3.8m +[2026-02-20T18:12:07.573824] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:12:07.574050] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:12:07.574076] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:12:07.602804] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:07.752914] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0d 00 00 00 8a 23 00 00 +[2026-02-20T18:12:07.753029] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:07.753055] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:12:08.049957] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:12:08.050035] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:12:08.050058] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640227} +[2026-02-20T18:12:08.050078] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:12:08.050103] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:12:08.050485] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:12:08.050510] LOG: [APP] Upload success: +1 items (total: 47) +[2026-02-20T18:12:08.076209] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:12:08.076275] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:12:09.196952] LOG: [CONN] Frame received (83 bytes): 88 31 c0 15 0c cc 1b 9d 50 7e 75 20 20 53 1f 9d cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d +[2026-02-20T18:12:09.197100] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:12:09.197144] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:12:09.197222] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:12:09.197245] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:12:09.197265] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:12:09.197301] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-64, payload=66 bytes +[2026-02-20T18:12:09.197315] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:12:09.197331] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:12:09.197342] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:12:09.197354] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 1B +[2026-02-20T18:12:09.197425] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:12:09.197442] LOG: [RX FILTER] Raw packet (80 bytes): 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:12:09.197465] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 +[2026-02-20T18:12:09.197475] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:12:09.197486] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:12:09.197501] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:12:09.197515] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:12:09.197527] LOG: [RX FILTER] Encrypted message: 63 bytes +[2026-02-20T18:12:09.197543] LOG: [CRYPTO] Decrypting message (63 bytes) +[2026-02-20T18:12:09.197718] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:09.197770] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:09.198006] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:12:09.198134] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:12:09.198146] LOG: [RX LOG] Dropped packet hex: 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:12:11.770700] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.13761, accuracy=3.8m +[2026-02-20T18:12:12.602627] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:12.703388] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c0 31 0d 00 00 00 8a 23 00 00 +[2026-02-20T18:12:12.703530] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:12.703563] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:12:13.051974] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:12:16.768124] LOG: [GPS SERVICE] Position stream fired: lat=47.35793, lon=-122.13646, accuracy=3.8m +[2026-02-20T18:12:17.603008] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:17.714705] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c0 31 0d 00 00 00 8a 23 00 00 +[2026-02-20T18:12:17.714841] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:17.714861] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:19.393358] LOG: [CONN] Frame received (90 bytes): 88 2f c2 15 15 cc 1b 9d 50 7e 75 20 20 20 53 d1 7a b8 1f fb 47 b0 a5 c7 db cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee e6 +[2026-02-20T18:12:19.393516] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:12:19.393552] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:12:19.393637] LOG: [RX PARSE] RAW Packet (87 bytes): 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 +[2026-02-20T18:12:19.393660] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:12:19.393672] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:12:19.393699] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=64 bytes +[2026-02-20T18:12:19.393713] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:12:19.393723] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:12:19.393738] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:12:19.393752] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 1B +[2026-02-20T18:12:19.393828] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:12:19.393845] LOG: [RX FILTER] Raw packet (87 bytes): 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 +[2026-02-20T18:12:19.393866] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 11.75 +[2026-02-20T18:12:19.393880] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:12:19.393892] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:12:19.393902] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:12:19.393920] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:12:19.393936] LOG: [RX FILTER] Encrypted message: 61 bytes +[2026-02-20T18:12:19.393947] LOG: [CRYPTO] Decrypting message (61 bytes) +[2026-02-20T18:12:19.394137] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:19.394187] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:19.394424] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:12:19.394963] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:12:19.395005] LOG: [RX LOG] Dropped packet hex: 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 +[2026-02-20T18:12:21.778272] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.13539, accuracy=3.8m +[2026-02-20T18:12:22.573688] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:12:22.573794] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:12:22.603244] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:22.755404] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:22.755530] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:22.755548] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:26.768010] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13431, accuracy=3.8m +[2026-02-20T18:12:26.768055] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:12:26.768119] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:12:27.603813] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:12:27.603958] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:27.766081] LOG: [CONN] Frame received (11 bytes): 0c f7 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:12:27.766219] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:12:27.766237] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:12:27.766253] LOG: [CONN] Battery updated: 4087mV (91%) +[2026-02-20T18:12:27.822782] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:27.822857] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:27.822869] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:31.777690] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13318, accuracy=3.8m +[2026-02-20T18:12:32.602814] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:32.684724] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c2 2f 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:32.684855] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:32.684875] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:12:33.073140] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:12:33.073299] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:12:33.073318] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:12:33.073360] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:12:33.073408] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35794, -122.13318 [0.3w]" +[2026-02-20T18:12:33.073421] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:12:33.073435] LOG: [TX LOG] Payload: "@[MapperBot] 47.35794, -122.13318 [0.3w]" +[2026-02-20T18:12:33.073449] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:12:33.073461] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:12:33.073479] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:12:33.073489] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:12:33.073516] LOG: [CONN] Sending ping: @[MapperBot] 47.35794, -122.13318 [0.3w] +[2026-02-20T18:12:33.193003] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:12:33.193137] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:12:33.193150] LOG: [CONN] Received OK response +[2026-02-20T18:12:34.798984] LOG: [CONN] Frame received (73 bytes): 88 32 c2 15 01 cc 81 4e b1 9e c0 60 a7 8f 70 2e ac 9b 9e 75 97 18 0e 23 3d 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 1f 05 62 ca bf 9e d9 c1 b8 a5 4d ac c1 a3 2d b7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:12:34.799086] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:12:34.799109] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:12:34.799153] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 4E B1 9E C0 60 A7 8F 70 2E AC 9B 9E 75 97 18 0E 23 3D 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 1F 05 62 CA BF 9E D9 C1 B8 A5 4D AC C1 A3 2D B7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:12:34.799163] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:12:34.799173] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:12:34.799192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-62, payload=67 bytes +[2026-02-20T18:12:34.799204] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:12:34.799209] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:12:34.799216] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-62 +[2026-02-20T18:12:34.799225] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:12:34.799231] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:12:34.799244] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:12:34.799257] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:12:34.799263] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:12:36.193752] LOG: [PING] Ping sent successfully +[2026-02-20T18:12:36.793723] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.13200, accuracy=3.8m +[2026-02-20T18:12:37.574838] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:12:37.574974] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:12:37.602963] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:37.696033] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c2 32 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:37.696168] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:37.696189] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:12:38.075243] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:12:41.196177] LOG: [PING] RX listening window ended +[2026-02-20T18:12:41.196344] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:12:41.196378] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:12:41.196480] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:12:41.196494] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:12:41.196506] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:12:41.196536] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:12:41.196551] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:12:41.197003] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:12:41.771269] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.13087, accuracy=3.8m +[2026-02-20T18:12:42.603234] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:42.706777] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:42.706818] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:42.706823] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:46.203767] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:12:46.204043] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:12:46.204056] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:12:46.760529] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.12985, accuracy=3.8m +[2026-02-20T18:12:46.831932] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:12:46.831963] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:12:46.831968] LOG: [API] Response (200) in 0.63s: {"success":true,"expires_at":1771640266} +[2026-02-20T18:12:46.831974] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:12:46.831980] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:12:46.832183] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:12:46.832189] LOG: [APP] Upload success: +1 items (total: 48) +[2026-02-20T18:12:47.603794] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:47.714345] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0d 00 00 00 8b 23 00 00 +[2026-02-20T18:12:47.714394] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:47.714400] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:48.717797] LOG: [CONN] Frame received (162 bytes): 88 2d ba 15 0b af d1 86 67 38 75 20 20 75 7e cc 11 93 3c 07 9e 13 18 5e f4 ec 28 a0 53 de f2 a2 2d 8a 78 94 00 55 c7 e6 bd 6c cb 71 6b 8f fc 48 91 32 f0 1a 63 e8 9e 24 9d b8 ad 04 d6 37 e5 13 bf 33 d1 6d df d1 8c 6a b8 dd 94 a9 3e f6 b6 15 8e e8 00 29 3e e9 5c 32 24 a3 ec cd 61 b3 a6 e9 71 18 88 6d 22 67 5d 51 49 36 8e 24 0f 18 c2 58 b4 5b 59 6d 2f f8 1d 8d 5d 05 0b 6f 79 f7 10 f2 b7 a5 bc 86 22 e4 21 83 67 fd 42 a1 d4 54 51 c4 b7 26 d3 b0 48 81 16 4b ad 6b 27 a1 7f 0f 1f 45 38 d1 +[2026-02-20T18:12:48.717876] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:12:48.717893] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:12:48.717942] LOG: [RX PARSE] RAW Packet (159 bytes): 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 +[2026-02-20T18:12:48.717952] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:12:48.717960] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:12:48.717978] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xaf, lastHop=0xcc, SNR=11.25, RSSI=-70, payload=146 bytes +[2026-02-20T18:12:48.717986] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:12:48.717992] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:12:48.717996] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:12:48.718043] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:12:48.718050] LOG: [RX FILTER] Raw packet (159 bytes): 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 +[2026-02-20T18:12:48.718063] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 11.25 +[2026-02-20T18:12:48.718070] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) +[2026-02-20T18:12:48.718075] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:12:48.718083] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:12:48.718088] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:12:48.718092] LOG: [RX FILTER] Encrypted message: 143 bytes +[2026-02-20T18:12:48.718100] LOG: [CRYPTO] Decrypting message (143 bytes) +[2026-02-20T18:12:48.718232] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:48.718258] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:12:48.718371] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:12:48.718439] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:12:48.718443] LOG: [RX LOG] Dropped packet hex: 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 +[2026-02-20T18:12:51.784824] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12911, accuracy=3.8m +[2026-02-20T18:12:51.834821] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:12:52.573739] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:12:52.573807] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:12:52.604391] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:52.720963] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:12:52.721012] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:52.721017] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:12:56.761962] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.12850, accuracy=3.8m +[2026-02-20T18:12:57.602829] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:12:57.603010] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:12:57.675862] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:12:57.676001] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:12:57.676021] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:12:57.676038] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T18:12:57.733255] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:12:57.733354] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:12:57.733378] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:01.793809] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.12814, accuracy=3.8m +[2026-02-20T18:13:01.793851] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:13:01.793911] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:13:02.602847] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:02.743796] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:02.743901] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:02.743920] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:06.795902] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12786, accuracy=3.9m +[2026-02-20T18:13:07.574041] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:13:07.574211] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:13:07.602896] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:07.754357] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:07.754501] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:07.754555] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:11.198947] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:13:11.199105] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:13:11.199124] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:13:11.199173] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:13:11.199216] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35798, -122.12786 [0.3w]" +[2026-02-20T18:13:11.199244] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:13:11.199254] LOG: [TX LOG] Payload: "@[MapperBot] 47.35798, -122.12786 [0.3w]" +[2026-02-20T18:13:11.199268] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:13:11.199287] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:13:11.199299] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:13:11.199309] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:13:11.199336] LOG: [CONN] Sending ping: @[MapperBot] 47.35798, -122.12786 [0.3w] +[2026-02-20T18:13:11.262669] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:13:11.262764] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:13:11.262774] LOG: [CONN] Received OK response +[2026-02-20T18:13:11.805077] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12750, accuracy=16.8m +[2026-02-20T18:13:12.104758] LOG: [CONN] Frame received (73 bytes): 88 2e c3 15 01 cc 81 21 0d 9e 34 1f c0 6e 0a 3e 49 67 38 c0 49 0a c1 f7 79 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 00 f6 49 89 85 63 fd b3 ac 89 7c 21 30 a2 52 41 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:13:12.104811] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:12.104820] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:12.104836] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 21 0D 9E 34 1F C0 6E 0A 3E 49 67 38 C0 49 0A C1 F7 79 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 00 F6 49 89 85 63 FD B3 AC 89 7C 21 30 A2 52 41 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:13:12.104840] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:12.104843] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:13:12.104852] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=67 bytes +[2026-02-20T18:13:12.104856] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:13:12.104858] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:13:12.104862] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-61 +[2026-02-20T18:13:12.104864] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:13:12.104866] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:13:12.104871] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:12.104873] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:12.104875] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:13:12.604031] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:12.765278] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c3 2e 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:12.765426] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:12.765446] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:13:14.269875] LOG: [PING] Ping sent successfully +[2026-02-20T18:13:16.200374] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:13:16.793558] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.12704, accuracy=3.8m +[2026-02-20T18:13:17.602937] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:17.774182] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:17.774283] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:17.774299] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:19.271566] LOG: [PING] RX listening window ended +[2026-02-20T18:13:19.271715] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:13:19.271749] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:13:19.271825] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:13:19.271837] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:13:19.271850] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:13:19.271879] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:13:19.271893] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:13:19.272322] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:13:21.792192] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12682, accuracy=3.9m +[2026-02-20T18:13:22.573623] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:13:22.573730] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:13:22.573736] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:13:22.602743] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:22.752952] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:22.753108] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:22.753133] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:23.043616] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:13:23.043711] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:13:23.043732] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640302} +[2026-02-20T18:13:23.043752] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:13:23.043787] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:13:23.044491] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:13:23.044519] LOG: [APP] Upload success: +1 items (total: 49) +[2026-02-20T18:13:24.273649] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:13:24.273805] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:13:27.602779] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:13:27.602903] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:27.761241] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:13:27.761313] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:13:27.761318] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:13:27.761323] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:13:27.823455] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:27.823598] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:27.823625] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:28.048369] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:13:30.060884] LOG: [CONN] Frame received (45 bytes): 88 2f cc 15 05 af d1 86 9d cc 72 9c 2e 66 1b 2d 35 15 e3 2f 3f 26 d2 28 6c a7 c8 dc f3 a9 3c 66 1b 39 b2 6d cd 15 79 ad b1 13 3d 84 6b +[2026-02-20T18:13:30.061018] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:30.061046] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:30.061086] LOG: [RX PARSE] RAW Packet (42 bytes): 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B +[2026-02-20T18:13:30.061104] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:30.061113] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:13:30.061143] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0xaf, lastHop=0xcc, SNR=11.75, RSSI=-52, payload=35 bytes +[2026-02-20T18:13:30.061154] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 +[2026-02-20T18:13:30.061166] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:30.061176] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:30.061210] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:13:30.061219] LOG: [RX FILTER] Raw packet (42 bytes): 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B +[2026-02-20T18:13:30.061242] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 11.75 +[2026-02-20T18:13:30.061253] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:13:30.061266] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:13:30.061275] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:13:30.061283] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:13:30.061329] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:13:30.061337] LOG: [RX LOG] Dropped packet hex: 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B +[2026-02-20T18:13:31.787588] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12665, accuracy=4.6m +[2026-02-20T18:13:32.602640] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:32.651868] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2f 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:32.651921] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:32.651926] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:35.661485] LOG: [CONN] Frame received (47 bytes): 88 31 cc 15 07 43 37 6c 3e 32 db cc 72 d4 4a 40 aa 36 f7 e3 bd 9b d1 71 dd c4 0c d0 9e 91 9e 0c ef 46 6e 7f 60 c4 47 42 bf 92 5b 10 03 53 ab +[2026-02-20T18:13:35.661690] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:35.661735] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:35.661794] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB +[2026-02-20T18:13:35.661815] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:35.661823] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:13:35.661947] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x43, lastHop=0xcc, SNR=12.25, RSSI=-52, payload=35 bytes +[2026-02-20T18:13:35.661960] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:13:35.661967] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:35.661983] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:35.662025] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:13:35.662036] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB +[2026-02-20T18:13:35.662063] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 +[2026-02-20T18:13:35.662081] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:13:35.662097] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:13:35.662110] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:13:35.662120] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:13:35.662190] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:13:35.662199] LOG: [RX LOG] Dropped packet hex: 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB +[2026-02-20T18:13:37.573724] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:13:37.573818] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:13:37.605876] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:37.663444] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:37.663532] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:37.663547] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:42.602991] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:42.676365] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 0d 00 00 00 8c 23 00 00 +[2026-02-20T18:13:42.676494] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:42.676514] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:43.084240] LOG: [CONN] Frame received (130 bytes): 88 30 cc 15 0a 1f 7d c7 7e 7a 29 dc 8b 9d cc 72 17 7c 1e ee 7d cb cd b4 32 fa 4f 9d 75 a0 a4 8b 44 e0 69 91 b2 5c 6f a9 6a 90 0d e5 e7 5b b2 9c a0 51 3a 37 c6 0f 8a 9b 05 cf 06 65 a4 c1 6b c6 e4 23 55 2b 5a 3a f4 f2 a7 99 86 56 15 b9 e8 cc 60 13 aa bb b9 b5 36 3e 30 6a 56 2c 09 08 9e 79 f6 2e 66 f6 7f a9 8b e1 d8 99 93 1b 22 f2 14 08 9e c3 34 98 1c b2 66 a6 57 06 08 08 a2 d2 bd af 0e 1d +[2026-02-20T18:13:43.084401] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:43.084431] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:43.084541] LOG: [RX PARSE] RAW Packet (127 bytes): 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D +[2026-02-20T18:13:43.084567] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:43.084578] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:13:43.084613] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x1f, lastHop=0xcc, SNR=12.0, RSSI=-52, payload=115 bytes +[2026-02-20T18:13:43.084627] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:13:43.084642] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:43.084654] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:43.084756] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:13:43.084768] LOG: [RX FILTER] Raw packet (127 bytes): 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D +[2026-02-20T18:13:43.084794] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.0 +[2026-02-20T18:13:43.084813] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:13:43.084824] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:13:43.084834] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:13:43.084849] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:13:43.084971] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:13:43.084987] LOG: [RX LOG] Dropped packet hex: 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D +[2026-02-20T18:13:44.520026] LOG: [CONN] Frame received (129 bytes): 88 32 ce 15 0b 1f 7d c7 7e 75 20 20 20 75 7e cc 72 17 7c 1e ee 7d cb cd b4 32 fa 4f 9d 75 a0 a4 8b 44 e0 69 91 b2 5c 6f a9 6a 90 0d e5 e7 5b b2 9c a0 51 3a 37 c6 0f 8a 9b 05 cf 06 65 a4 c1 6b c6 e4 23 55 2b 5a 3a f4 f2 a7 99 86 56 15 b9 e8 cc 60 13 aa bb b9 b5 36 3e 30 6a 56 2c 09 08 9e 79 f6 2e 66 f6 7f a9 8b e1 d8 99 93 1b 22 f2 14 08 9e c3 34 98 1c b2 66 a6 57 06 08 08 a2 d2 bd af +[2026-02-20T18:13:44.520182] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:44.520217] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:44.520326] LOG: [RX PARSE] RAW Packet (126 bytes): 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF +[2026-02-20T18:13:44.520350] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:44.520361] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:13:44.520395] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-50, payload=113 bytes +[2026-02-20T18:13:44.520410] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 +[2026-02-20T18:13:44.520420] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:44.520434] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:44.520534] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:13:44.520545] LOG: [RX FILTER] Raw packet (126 bytes): 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF +[2026-02-20T18:13:44.520570] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 +[2026-02-20T18:13:44.520584] LOG: [RX FILTER] ✓ RSSI OK (-50 < -30) +[2026-02-20T18:13:44.520599] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:13:44.520610] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:13:44.520620] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:13:44.520887] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:13:44.520919] LOG: [RX LOG] Dropped packet hex: 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF +[2026-02-20T18:13:47.602908] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:47.712962] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 32 0d 00 00 00 8d 23 00 00 +[2026-02-20T18:13:47.713098] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:47.713118] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:49.273898] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:13:49.274038] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:13:49.274065] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:13:49.274107] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:13:49.274152] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35798, -122.12665 [0.3w]" +[2026-02-20T18:13:49.274165] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:13:49.274188] LOG: [TX LOG] Payload: "@[MapperBot] 47.35798, -122.12665 [0.3w]" +[2026-02-20T18:13:49.274201] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:13:49.274214] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:13:49.274230] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:13:49.274242] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:13:49.274264] LOG: [CONN] Sending ping: @[MapperBot] 47.35798, -122.12665 [0.3w] +[2026-02-20T18:13:49.425342] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:13:49.425486] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:13:49.425499] LOG: [CONN] Received OK response +[2026-02-20T18:13:50.280780] LOG: [CONN] Frame received (73 bytes): 88 31 cb 15 01 cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:13:50.280900] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:50.280921] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:50.280975] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:13:50.280990] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:50.281] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:13:50.281057] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-53, payload=67 bytes +[2026-02-20T18:13:50.281072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:13:50.281080] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:13:50.281088] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-53 +[2026-02-20T18:13:50.281101] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:13:50.281108] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:13:50.281120] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:50.281128] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:50.281135] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:13:52.425048] LOG: [PING] Ping sent successfully +[2026-02-20T18:13:52.573715] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:13:52.573857] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:13:52.602726] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:52.754226] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0e 00 00 00 8d 23 00 00 +[2026-02-20T18:13:52.754358] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:52.754382] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:54.276406] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:13:57.425812] LOG: [PING] RX listening window ended +[2026-02-20T18:13:57.425886] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:13:57.425917] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:13:57.425978] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:13:57.425988] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:13:57.426005] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:13:57.426027] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:13:57.426045] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:13:57.442659] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:13:57.604486] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:13:57.604651] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:13:57.762287] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:13:57.762367] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:13:57.762375] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:13:57.762385] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:13:57.823312] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0e 00 00 00 8d 23 00 00 +[2026-02-20T18:13:57.823468] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:13:57.823487] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:13:59.869456] LOG: [CONN] Frame received (84 bytes): 88 30 cb 15 0d cc db c7 7e 75 20 20 75 38 24 7a 9d cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d +[2026-02-20T18:13:59.869609] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:13:59.869638] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:13:59.869716] LOG: [RX PARSE] RAW Packet (81 bytes): 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:13:59.869747] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:13:59.869758] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:13:59.869785] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-53, payload=66 bytes +[2026-02-20T18:13:59.869798] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:13:59.869813] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:13:59.869825] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:13:59.869837] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:13:59.869907] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:13:59.869923] LOG: [RX FILTER] Raw packet (81 bytes): 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:13:59.869941] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.0 +[2026-02-20T18:13:59.869956] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:13:59.869967] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:13:59.869977] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:13:59.869994] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:13:59.870007] LOG: [RX FILTER] Encrypted message: 63 bytes +[2026-02-20T18:13:59.870018] LOG: [CRYPTO] Decrypting message (63 bytes) +[2026-02-20T18:13:59.870204] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:13:59.870257] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:13:59.870493] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:13:59.870695] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:13:59.870705] LOG: [RX LOG] Dropped packet hex: 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:14:02.444276] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:14:02.444325] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:14:02.444331] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:14:02.603176] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:02.652828] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 30 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:02.652956] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:02.652975] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:02.927392] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:14:02.927441] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:14:02.927448] LOG: [API] Response (200) in 0.48s: {"success":true,"expires_at":1771640342} +[2026-02-20T18:14:02.927459] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:14:02.927514] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:14:02.927687] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:14:02.927696] LOG: [APP] Upload success: +1 items (total: 50) +[2026-02-20T18:14:05.147102] LOG: [CONN] Frame received (86 bytes): 88 32 cc 15 13 cc db c7 7e 75 20 20 20 20 20 20 75 c5 26 07 a5 47 9d cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 +[2026-02-20T18:14:05.147232] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:05.147263] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:05.147322] LOG: [RX PARSE] RAW Packet (83 bytes): 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 +[2026-02-20T18:14:05.147336] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:14:05.147349] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:14:05.147368] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-52, payload=62 bytes +[2026-02-20T18:14:05.147383] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:14:05.147394] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:05.147401] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:05.147415] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:14:05.147476] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:14:05.147485] LOG: [RX FILTER] Raw packet (83 bytes): 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 +[2026-02-20T18:14:05.147505] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.5 +[2026-02-20T18:14:05.147513] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:14:05.147526] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:14:05.147537] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:14:05.147547] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:14:05.147561] LOG: [RX FILTER] Encrypted message: 59 bytes +[2026-02-20T18:14:05.147572] LOG: [CRYPTO] Decrypting message (59 bytes) +[2026-02-20T18:14:05.147719] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:14:05.147760] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:14:05.147936] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:14:05.148034] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:14:05.148044] LOG: [RX LOG] Dropped packet hex: 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 +[2026-02-20T18:14:07.573645] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:14:07.573700] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:14:07.602819] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:07.785878] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:07.786021] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:07.786043] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:07.928620] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:14:12.602930] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:12.645506] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:12.645627] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:12.645645] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:17.604415] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:17.713262] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:17.713337] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:17.713349] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:21.772109] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12583, accuracy=5.1m +[2026-02-20T18:14:21.772151] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:14:21.772206] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:14:22.574129] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:14:22.574303] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:14:22.605031] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:22.757223] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cc 32 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:22.757350] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:22.757376] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:14:26.804161] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.12495, accuracy=3.8m +[2026-02-20T18:14:27.426712] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:14:27.426839] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:14:27.426854] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:14:27.426886] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:14:27.426921] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35803, -122.12495 [0.3w]" +[2026-02-20T18:14:27.426929] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:14:27.426933] LOG: [TX LOG] Payload: "@[MapperBot] 47.35803, -122.12495 [0.3w]" +[2026-02-20T18:14:27.426946] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:14:27.426953] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:14:27.426959] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:14:27.426967] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:14:27.426981] LOG: [CONN] Sending ping: @[MapperBot] 47.35803, -122.12495 [0.3w] +[2026-02-20T18:14:27.603332] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:14:27.603551] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:27.616331] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:14:27.616420] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:14:27.616430] LOG: [CONN] Received OK response +[2026-02-20T18:14:27.675669] LOG: [CONN] Frame received (11 bytes): 0c c5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:14:27.675793] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:14:27.675811] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:14:27.675834] LOG: [CONN] Battery updated: 4037mV (86%) +[2026-02-20T18:14:27.733932] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:27.734028] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:27.734046] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:29.787163] LOG: [CONN] Frame received (73 bytes): 88 30 c4 15 01 cc 81 9a 98 50 2f af 06 51 3e e2 dd 2e 84 fa f4 41 d5 c4 92 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 8c 1b 1b 42 16 eb 90 0f 1c 73 ba ce 7c ea 0d 7f 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:14:29.787230] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:29.787243] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:29.787267] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 9A 98 50 2F AF 06 51 3E E2 DD 2E 84 FA F4 41 D5 C4 92 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 8C 1B 1B 42 16 EB 90 0F 1C 73 BA CE 7C EA 0D 7F 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:14:29.787273] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:14:29.787277] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:14:29.787286] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes +[2026-02-20T18:14:29.787290] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:14:29.787295] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:14:29.787299] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-60 +[2026-02-20T18:14:29.787302] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:14:29.787306] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:14:29.787310] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:29.787313] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:29.787318] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:14:30.617449] LOG: [PING] Ping sent successfully +[2026-02-20T18:14:31.772574] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.12443, accuracy=3.9m +[2026-02-20T18:14:32.427750] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:14:32.602947] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:32.686166] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0e 00 00 00 8e 23 00 00 +[2026-02-20T18:14:32.686306] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:32.686326] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:35.618456] LOG: [PING] RX listening window ended +[2026-02-20T18:14:35.618680] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:14:35.618712] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:14:35.618780] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:14:35.618788] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:14:35.618801] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:14:35.618817] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:14:35.618828] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:14:35.619459] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:14:36.771619] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.12384, accuracy=4.2m +[2026-02-20T18:14:37.426856] LOG: [CONN] Frame received (85 bytes): 88 2e c3 15 10 0a 53 7e 67 75 20 20 20 20 75 a5 e8 32 34 9d cc 11 71 a8 8f b5 48 f9 c6 76 0b 84 55 56 8b fa 54 ae f4 d4 0e 96 ac 16 b3 63 f8 4e 5f 88 78 d3 6c c7 36 a6 a5 da 7c 78 25 b6 43 5e 6a 7e 96 8d 40 f9 64 5a a7 aa 03 44 cc 24 06 e9 e3 b1 1a cb 4b +[2026-02-20T18:14:37.427028] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:37.427062] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:37.427154] LOG: [RX PARSE] RAW Packet (82 bytes): 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B +[2026-02-20T18:14:37.427178] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:14:37.427189] LOG: [RX PARSE] Path length offset: 1, Path length: 16 +[2026-02-20T18:14:37.427227] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=16, firstHop=0x0a, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=64 bytes +[2026-02-20T18:14:37.427242] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=16 +[2026-02-20T18:14:37.427257] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:37.427270] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:37.427346] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:14:37.427357] LOG: [RX FILTER] Raw packet (82 bytes): 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B +[2026-02-20T18:14:37.427381] LOG: [RX FILTER] Header: 0x15 | PathLength: 16 | SNR: 11.5 +[2026-02-20T18:14:37.427395] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:14:37.427412] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:14:37.427424] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:14:37.427435] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:14:37.427453] LOG: [RX FILTER] Encrypted message: 61 bytes +[2026-02-20T18:14:37.427464] LOG: [CRYPTO] Decrypting message (61 bytes) +[2026-02-20T18:14:37.427673] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:14:37.427728] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:14:37.427968] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:14:37.428106] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:14:37.428118] LOG: [RX LOG] Dropped packet hex: 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B +[2026-02-20T18:14:37.574146] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:14:37.574381] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:14:37.574409] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:14:37.602666] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:37.786225] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:14:37.786318] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:37.786336] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:38.245522] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:14:38.245577] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:14:38.245587] LOG: [API] Response (200) in 0.67s: {"success":true,"expires_at":1771640378} +[2026-02-20T18:14:38.245601] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:14:38.245612] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:14:38.245895] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:14:38.245905] LOG: [APP] Upload success: +1 items (total: 51) +[2026-02-20T18:14:40.620551] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:14:40.620773] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:14:41.784171] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.12306, accuracy=4.6m +[2026-02-20T18:14:42.605819] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:42.794] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:14:42.794134] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:42.794159] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:43.246969] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:14:46.063776] LOG: [CONN] Frame received (131 bytes): 88 2f c3 11 05 0c 64 c7 db cc 17 54 0f 83 fd 5b 05 3c 3e 19 e8 56 da dc b4 6b d2 0a da 33 9f 37 74 22 3a 0e 0a a9 61 9a cb f9 f0 f1 5e 66 1e 11 22 1e 60 b6 fd e0 5b b9 29 13 45 ce a9 4d 45 7c 41 76 43 3a 6a b0 4f e0 f8 bb 33 02 00 dd 92 3b db 1e 1e a3 53 a5 1a a9 61 f0 ab b3 86 96 09 6f 6a 73 99 a4 13 00 98 ff d9 67 4c 93 58 0a 92 00 00 00 00 00 00 00 00 f0 9f 90 87 f0 9f 90 87 f0 9f 90 87 +[2026-02-20T18:14:46.063870] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:46.063892] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:46.063941] LOG: [RX PARSE] RAW Packet (128 bytes): 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 +[2026-02-20T18:14:46.063953] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:14:46.063958] LOG: [RX PARSE] Path length offset: 1, Path length: 5 +[2026-02-20T18:14:46.063978] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x0c, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=121 bytes +[2026-02-20T18:14:46.063986] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 +[2026-02-20T18:14:46.063990] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:46.064359] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:46.064409] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:14:46.064414] LOG: [RX FILTER] Raw packet (128 bytes): 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 +[2026-02-20T18:14:46.064445] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 11.75 +[2026-02-20T18:14:46.064455] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:14:46.064461] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:14:46.064465] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:14:46.064475] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:14:46.064549] LOG: [RX FILTER] ADVERT name extracted: "🐇🐇🐇" (6 chars) +[2026-02-20T18:14:46.064557] LOG: [RX FILTER] ADVERT name printable ratio: 0.0% +[2026-02-20T18:14:46.064565] LOG: [RX FILTER] ❌ DROPPED: name not printable +[2026-02-20T18:14:46.064617] LOG: [RX LOG] ❌ Packet dropped: name not printable +[2026-02-20T18:14:46.064624] LOG: [RX LOG] Dropped packet hex: 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 +[2026-02-20T18:14:46.064856] LOG: [CONN] Frame received (33 bytes): 80 17 54 0f 83 fd 5b 05 3c 3e 19 e8 56 da dc b4 6b d2 0a da 33 9f 37 74 22 3a 0e 0a a9 61 9a cb f9 +[2026-02-20T18:14:46.064865] LOG: [CONN] Response code: 0x80 (128) +[2026-02-20T18:14:46.064870] LOG: [CONN] Unhandled frame: code=128 (0x80) +[2026-02-20T18:14:46.427122] LOG: [CONN] Frame received (44 bytes): 88 2e c3 15 04 62 1f db cc 72 67 b2 b8 a0 85 a8 9e fa 04 00 f4 4e 06 ce f9 04 20 56 62 e4 1b cb 9e 4a 5b 80 4c c3 5e 4e 5c a2 70 25 +[2026-02-20T18:14:46.427180] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:46.427220] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:46.427267] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 +[2026-02-20T18:14:46.427288] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:14:46.427300] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:14:46.427323] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x62, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=35 bytes +[2026-02-20T18:14:46.427341] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:14:46.427352] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:46.427360] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:46.427409] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:14:46.427420] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 +[2026-02-20T18:14:46.427436] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 +[2026-02-20T18:14:46.427456] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:14:46.427468] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:14:46.427478] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:14:46.427495] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:14:46.427673] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:14:46.427687] LOG: [RX LOG] Dropped packet hex: 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 +[2026-02-20T18:14:46.765899] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.12219, accuracy=4.2m +[2026-02-20T18:14:47.602986] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:47.686427] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:14:47.686723] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:47.686754] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:52.104476] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.12130, accuracy=4.2m +[2026-02-20T18:14:52.104530] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:14:52.104587] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:14:52.574410] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:14:52.574690] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:14:52.603017] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:54.882822] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:14:54.882962] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:54.882982] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:56.797779] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.12048, accuracy=4.5m +[2026-02-20T18:14:57.603565] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:14:57.603796] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:14:57.795952] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:14:57.796090] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:14:57.796109] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:14:57.796125] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:14:57.854219] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:14:57.854348] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:14:57.854372] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:14:59.461750] LOG: [CONN] Frame received (57 bytes): 88 30 c3 15 12 62 1f c5 75 20 20 75 e9 24 43 6f 9b f7 13 c7 34 9d cc 72 67 b2 b8 a0 85 a8 9e fa 04 00 f4 4e 06 ce f9 04 20 56 62 e4 1b cb 9e 4a 5b 80 4c c3 5e 4e 5c a2 70 +[2026-02-20T18:14:59.461905] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:14:59.461942] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:14:59.462003] LOG: [RX PARSE] RAW Packet (54 bytes): 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 +[2026-02-20T18:14:59.462025] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:14:59.462039] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:14:59.462080] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x62, lastHop=0xcc, SNR=12.0, RSSI=-61, payload=34 bytes +[2026-02-20T18:14:59.462095] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T18:14:59.462111] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:14:59.462125] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:14:59.462189] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:14:59.462208] LOG: [RX FILTER] Raw packet (54 bytes): 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 +[2026-02-20T18:14:59.462225] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.0 +[2026-02-20T18:14:59.462245] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:14:59.462255] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:14:59.462266] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:14:59.462283] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:14:59.462353] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:14:59.462365] LOG: [RX LOG] Dropped packet hex: 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 +[2026-02-20T18:15:01.788969] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.11987, accuracy=4.3m +[2026-02-20T18:15:02.604851] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:02.651491] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0e 00 00 00 8f 23 00 00 +[2026-02-20T18:15:02.651562] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:02.651574] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:05.620640] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:15:05.620801] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:15:05.620820] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:15:05.620870] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:15:05.620915] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35804, -122.11987 [0.3w]" +[2026-02-20T18:15:05.620932] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:15:05.620942] LOG: [TX LOG] Payload: "@[MapperBot] 47.35804, -122.11987 [0.3w]" +[2026-02-20T18:15:05.620956] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:15:05.620974] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:15:05.620987] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:15:05.620998] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:15:05.621031] LOG: [CONN] Sending ping: @[MapperBot] 47.35804, -122.11987 [0.3w] +[2026-02-20T18:15:05.713110] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:15:05.713240] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:15:05.713254] LOG: [CONN] Received OK response +[2026-02-20T18:15:05.830990] LOG: [CONN] Frame received (55 bytes): 88 31 c3 15 15 1f 2c 43 fb 23 7e 75 20 20 20 20 20 20 20 20 20 75 d6 53 7e cc 72 29 0b 56 9c 67 93 da 5f 1e d2 a4 ec 5b bb cd 93 1f ce 10 11 3c a4 45 30 26 20 cd 2d +[2026-02-20T18:15:05.831050] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:05.831062] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:05.831075] LOG: [RX PARSE] RAW Packet (52 bytes): 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D +[2026-02-20T18:15:05.831078] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:05.831082] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:15:05.831093] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=29 bytes +[2026-02-20T18:15:05.831098] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:15:05.831100] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:15:05.831103] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 +[2026-02-20T18:15:05.831107] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:15:05.831110] LOG: [TX LOG] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:15:05.831113] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x72, expected=0x81 +[2026-02-20T18:15:05.831116] LOG: [TX LOG] Ignoring: channel hash mismatch +[2026-02-20T18:15:05.831118] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:05.831121] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:05.831134] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:05.831136] LOG: [RX FILTER] Raw packet (52 bytes): 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D +[2026-02-20T18:15:05.831140] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.25 +[2026-02-20T18:15:05.831143] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) +[2026-02-20T18:15:05.831147] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:05.831149] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:15:05.831152] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:15:05.831167] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:05.831170] LOG: [RX LOG] Dropped packet hex: 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D +[2026-02-20T18:15:06.780798] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.11967, accuracy=4.2m +[2026-02-20T18:15:07.124532] LOG: [CONN] Frame received (73 bytes): 88 33 c4 15 01 cc 81 68 b6 f0 d7 80 fa 36 70 1b b9 5d 1b 97 67 c9 98 a3 b2 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 67 bb de df 1f 37 f9 f5 77 12 0f db 0e 5b 7d a0 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:15:07.124702] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:07.124733] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:07.124807] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 68 B6 F0 D7 80 FA 36 70 1B B9 5D 1B 97 67 C9 98 A3 B2 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 67 BB DE DF 1F 37 F9 F5 77 12 0F DB 0E 5B 7D A0 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:15:07.124828] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:07.124839] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:15:07.124876] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=67 bytes +[2026-02-20T18:15:07.124891] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:15:07.124901] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:15:07.124919] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-60 +[2026-02-20T18:15:07.124930] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:15:07.124945] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:15:07.124957] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:07.124967] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:07.124983] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:15:07.573691] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:15:07.573837] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:15:07.603060] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:07.782414] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c4 33 0e 00 00 00 90 23 00 00 +[2026-02-20T18:15:07.782631] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:07.782646] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:15:08.715004] LOG: [PING] Ping sent successfully +[2026-02-20T18:15:10.621990] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:15:11.795105] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.11944, accuracy=17.9m +[2026-02-20T18:15:12.602894] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:12.642128] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 90 23 00 00 +[2026-02-20T18:15:12.642196] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:12.642203] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:13.716550] LOG: [PING] RX listening window ended +[2026-02-20T18:15:13.716612] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:15:13.716626] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:15:13.716660] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:15:13.716663] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:15:13.716666] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:15:13.716672] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:15:13.716676] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:15:13.717045] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:15:15.731364] LOG: [CONN] Frame received (65 bytes): 88 31 c7 15 18 1f 2c 43 fb 23 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 6c 1b cc 72 29 0b 56 9c 67 93 da 5f 1e d2 a4 ec 5b bb cd 93 1f ce 10 11 3c a4 45 30 26 20 9e 4a 5b 80 4c c3 5e 4e dc +[2026-02-20T18:15:15.731411] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:15.731423] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:15.731448] LOG: [RX PARSE] RAW Packet (62 bytes): 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC +[2026-02-20T18:15:15.731453] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:15.731455] LOG: [RX PARSE] Path length offset: 1, Path length: 24 +[2026-02-20T18:15:15.731463] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=24, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=36 bytes +[2026-02-20T18:15:15.731466] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=24 +[2026-02-20T18:15:15.731469] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:15.731472] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:15.731485] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:15.731487] LOG: [RX FILTER] Raw packet (62 bytes): 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC +[2026-02-20T18:15:15.731491] LOG: [RX FILTER] Header: 0x15 | PathLength: 24 | SNR: 12.25 +[2026-02-20T18:15:15.731496] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:15:15.731498] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:15.731501] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:15:15.731504] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:15:15.731519] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:15.731521] LOG: [RX LOG] Dropped packet hex: 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC +[2026-02-20T18:15:16.769588] LOG: [GPS SERVICE] Position stream fired: lat=47.35809, lon=-122.11879, accuracy=5.0m +[2026-02-20T18:15:17.606407] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:17.696544] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0e 00 00 00 90 23 00 00 +[2026-02-20T18:15:17.696627] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:17.696634] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:18.468560] LOG: [APP] App resumed from background +[2026-02-20T18:15:18.717634] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:15:18.717736] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:15:18.717742] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:15:19.207503] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:15:19.207545] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:15:19.207552] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771640419} +[2026-02-20T18:15:19.207560] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:15:19.207571] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:15:19.207755] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:15:19.207768] LOG: [APP] Upload success: +1 items (total: 52) +[2026-02-20T18:15:21.107075] LOG: [CONN] Frame received (57 bytes): 88 31 c8 15 13 87 f7 7e 75 20 20 20 75 07 24 6f d1 c3 c3 7a 6c c7 db cc 72 20 a0 33 f5 7b 6d 51 50 a7 90 3d 7f 7a 5b 33 1a 77 29 3b 12 82 1d bd 7e 9c 7c 0b 4c c3 8f 89 a1 +[2026-02-20T18:15:21.107249] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:21.107279] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:21.107341] LOG: [RX PARSE] RAW Packet (54 bytes): 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 +[2026-02-20T18:15:21.107356] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:21.107373] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:15:21.107394] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x87, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=33 bytes +[2026-02-20T18:15:21.107412] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 +[2026-02-20T18:15:21.107423] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:21.107433] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:21.107488] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:21.107500] LOG: [RX FILTER] Raw packet (54 bytes): 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 +[2026-02-20T18:15:21.107529] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.25 +[2026-02-20T18:15:21.107543] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:15:21.107553] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:21.107569] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:15:21.107580] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:15:21.107644] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:21.107660] LOG: [RX LOG] Dropped packet hex: 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 +[2026-02-20T18:15:21.775978] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11792, accuracy=4.1m +[2026-02-20T18:15:22.574004] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:15:22.574251] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:15:22.604795] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:22.669827] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c8 31 0e 00 00 00 90 23 00 00 +[2026-02-20T18:15:22.669891] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:22.669900] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:15:24.210737] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:15:26.768115] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11699, accuracy=4.0m +[2026-02-20T18:15:26.768165] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:15:26.768235] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:15:27.602612] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:15:27.602732] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:27.671735] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:15:27.671793] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:15:27.671801] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:15:27.671808] LOG: [CONN] Battery updated: 4080mV (90%) +[2026-02-20T18:15:27.744170] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 31 0e 00 00 00 90 23 00 00 +[2026-02-20T18:15:27.744229] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:27.744233] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:29.293634] LOG: [CONN] Frame received (131 bytes): 88 30 c8 15 0c 1f 8b 18 7e 75 20 20 75 7e 6c db cc 72 6e 22 cd 32 b5 de 34 90 77 0b c6 de 2d 02 ac 62 2d 84 68 8a f4 88 a0 cc 0d d3 57 95 87 44 ef f8 05 e6 1a 5a 1e 7a 4a 30 a3 af 49 f7 68 36 ef 8e 90 04 cf 3a 5d 98 07 75 98 2b 4c 8c 73 b9 6f 80 e7 ef 16 90 d8 26 63 f5 98 5b b6 cc 93 b1 2f d1 fd ed 7f 37 a8 7c e1 41 aa 28 74 b4 e7 fb 81 75 08 00 60 ac 4f 5d 80 48 39 51 9f bc 3e fe fc 3d 32 +[2026-02-20T18:15:29.293747] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:29.293765] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:29.293806] LOG: [RX PARSE] RAW Packet (128 bytes): 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 +[2026-02-20T18:15:29.293815] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:29.293818] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:15:29.293832] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x1f, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=114 bytes +[2026-02-20T18:15:29.293838] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:15:29.293841] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:29.293847] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:29.293881] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:29.293884] LOG: [RX FILTER] Raw packet (128 bytes): 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 +[2026-02-20T18:15:29.293893] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.0 +[2026-02-20T18:15:29.293900] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:15:29.293905] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:29.293908] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:15:29.293914] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:15:29.293955] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:29.293960] LOG: [RX LOG] Dropped packet hex: 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 +[2026-02-20T18:15:31.786778] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11604, accuracy=4.0m +[2026-02-20T18:15:32.602726] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:32.652259] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 0e 00 00 00 91 23 00 00 +[2026-02-20T18:15:32.652329] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:32.652338] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:15:36.768826] LOG: [GPS SERVICE] Position stream fired: lat=47.35812, lon=-122.11547, accuracy=3.9m +[2026-02-20T18:15:37.573918] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:15:37.574104] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:15:37.603101] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:37.785884] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 0e 00 00 00 91 23 00 00 +[2026-02-20T18:15:37.785979] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:37.785992] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:15:40.576400] LOG: [CONN] Frame received (140 bytes): 88 32 c2 15 15 1f 8b 18 7e 7a 1e 5a ab 26 43 bf 56 fb e5 1b 5a cd 7a 7e db cc 72 6e 22 cd 32 b5 de 34 90 77 0b c6 de 2d 02 ac 62 2d 84 68 8a f4 88 a0 cc 0d d3 57 95 87 44 ef f8 05 e6 1a 5a 1e 7a 4a 30 a3 af 49 f7 68 36 ef 8e 90 04 cf 3a 5d 98 07 75 98 2b 4c 8c 73 b9 6f 80 e7 ef 16 90 d8 26 63 f5 98 5b b6 cc 93 b1 2f d1 fd ed 7f 37 a8 7c e1 41 aa 28 74 b4 e7 fb 81 75 08 00 60 ac 5d 80 48 39 51 9f bc 3e fe fc 3d 32 95 +[2026-02-20T18:15:40.576585] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:40.576624] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:40.576771] LOG: [RX PARSE] RAW Packet (137 bytes): 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 +[2026-02-20T18:15:40.576798] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:40.576809] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:15:40.576849] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-62, payload=114 bytes +[2026-02-20T18:15:40.576863] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:15:40.576880] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:40.576892] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:40.577007] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:40.577026] LOG: [RX FILTER] Raw packet (137 bytes): 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 +[2026-02-20T18:15:40.577056] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.5 +[2026-02-20T18:15:40.577074] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:15:40.577086] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:40.577105] LOG: [RX FILTER] Channel hash: 0x72 +[2026-02-20T18:15:40.577117] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 +[2026-02-20T18:15:40.577250] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:40.577262] LOG: [RX LOG] Dropped packet hex: 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 +[2026-02-20T18:15:41.765459] LOG: [GPS SERVICE] Position stream fired: lat=47.35810, lon=-122.11521, accuracy=3.8m +[2026-02-20T18:15:42.602803] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:42.731030] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0e 00 00 00 91 23 00 00 +[2026-02-20T18:15:42.731081] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:42.731088] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:43.136053] LOG: [APP] App resumed from background +[2026-02-20T18:15:43.718416] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:15:43.718575] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:15:43.718581] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:15:43.718601] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:15:43.718619] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35810, -122.11521 [0.3w]" +[2026-02-20T18:15:43.718623] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:15:43.718624] LOG: [TX LOG] Payload: "@[MapperBot] 47.35810, -122.11521 [0.3w]" +[2026-02-20T18:15:43.718635] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:15:43.718638] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:15:43.718641] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:15:43.718644] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:15:43.718651] LOG: [CONN] Sending ping: @[MapperBot] 47.35810, -122.11521 [0.3w] +[2026-02-20T18:15:43.843172] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:15:43.843248] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:15:43.843254] LOG: [CONN] Received OK response +[2026-02-20T18:15:45.584109] LOG: [CONN] Frame received (73 bytes): 88 31 c3 15 01 cc 81 df b9 79 20 81 c6 3b 83 44 e3 a2 d9 d2 ab 35 7f 10 18 e7 f6 79 96 7b 7a 1a 83 f2 2c 4f 28 76 21 94 70 40 bb 57 c2 49 f0 6e 91 c8 3c 6e e1 68 d3 eb 6e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:15:45.584243] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:45.584267] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:45.584323] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 DF B9 79 20 81 C6 3B 83 44 E3 A2 D9 D2 AB 35 7F 10 18 E7 F6 79 96 7B 7A 1A 83 F2 2C 4F 28 76 21 94 70 40 BB 57 C2 49 F0 6E 91 C8 3C 6E E1 68 D3 EB 6E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:15:45.584387] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:45.584395] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:15:45.584418] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=67 bytes +[2026-02-20T18:15:45.584429] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:15:45.584440] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:15:45.584452] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 +[2026-02-20T18:15:45.584460] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:15:45.584470] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:15:45.584480] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:45.584487] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:45.584500] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:15:46.787424] LOG: [GPS SERVICE] Position stream fired: lat=47.35813, lon=-122.11473, accuracy=16.5m +[2026-02-20T18:15:46.843717] LOG: [PING] Ping sent successfully +[2026-02-20T18:15:47.605022] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:47.743418] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0e 00 00 00 92 23 00 00 +[2026-02-20T18:15:47.743590] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:47.743637] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:48.720448] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:15:51.794664] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11386, accuracy=3.8m +[2026-02-20T18:15:51.844983] LOG: [PING] RX listening window ended +[2026-02-20T18:15:51.845153] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:15:51.845184] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:15:51.845260] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:15:51.845289] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:15:51.845304] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:15:51.845330] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:15:51.845351] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:15:51.857262] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:15:52.573736] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:15:52.573949] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:15:52.573966] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:15:52.602907] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:52.753383] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0e 00 00 00 92 23 00 00 +[2026-02-20T18:15:52.753534] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:52.753556] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:52.813340] LOG: [CONN] Frame received (64 bytes): 88 2f c4 15 09 d4 5e ca 29 1f 7a db 1b cc ad f7 34 05 f8 da eb f3 50 8d de f4 ba 96 ed ef c8 7b 67 07 7f 94 f4 32 13 77 e3 ec 2e 2a ab 04 90 af c1 c5 a1 90 0f df 6a 0d 8f 63 e9 9c 6a 99 f5 f1 +[2026-02-20T18:15:52.813430] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:52.813450] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:52.813489] LOG: [RX PARSE] RAW Packet (61 bytes): 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 +[2026-02-20T18:15:52.813499] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:52.813508] LOG: [RX PARSE] Path length offset: 1, Path length: 9 +[2026-02-20T18:15:52.813527] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0xd4, lastHop=0xcc, SNR=11.75, RSSI=-60, payload=50 bytes +[2026-02-20T18:15:52.813544] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 +[2026-02-20T18:15:52.813550] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:52.813556] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:52.813591] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:52.813598] LOG: [RX FILTER] Raw packet (61 bytes): 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 +[2026-02-20T18:15:52.813612] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 11.75 +[2026-02-20T18:15:52.813621] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:15:52.813630] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:52.813639] LOG: [RX FILTER] Channel hash: 0xad +[2026-02-20T18:15:52.813645] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad +[2026-02-20T18:15:52.813690] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:52.813700] LOG: [RX LOG] Dropped packet hex: 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 +[2026-02-20T18:15:53.103440] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:15:53.103569] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:15:53.103593] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771640452} +[2026-02-20T18:15:53.103615] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:15:53.103643] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:15:53.106866] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:15:53.106890] LOG: [APP] Upload success: +1 items (total: 53) +[2026-02-20T18:15:56.800706] LOG: [GPS SERVICE] Position stream fired: lat=47.35815, lon=-122.11296, accuracy=3.8m +[2026-02-20T18:15:56.800747] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:15:56.800809] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:15:56.861670] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:15:56.861762] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:15:57.602692] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:15:57.602827] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:15:57.676782] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:15:57.676912] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:15:57.676943] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:15:57.676960] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:15:57.735416] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0e 00 00 00 92 23 00 00 +[2026-02-20T18:15:57.735537] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:15:57.735563] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:15:58.108119] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:15:58.470341] LOG: [CONN] Frame received (68 bytes): 88 30 bd 15 0e d4 5e ca 29 1f 7a c5 75 20 20 75 7e 1b cc ad f7 34 05 f8 da eb f3 50 8d de f4 ba 96 ed ef c8 7b 67 07 7f 94 f4 32 13 77 e3 ec 2e 2a ab 04 90 af c1 c5 a1 90 0f df 6a 0d 8f 63 e9 9c 6a 99 f5 +[2026-02-20T18:15:58.470464] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:15:58.470494] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:15:58.470713] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 +[2026-02-20T18:15:58.470732] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:15:58.470749] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:15:58.470780] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xd4, lastHop=0xcc, SNR=12.0, RSSI=-67, payload=49 bytes +[2026-02-20T18:15:58.470799] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:15:58.470811] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:15:58.470820] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:15:58.470884] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:15:58.470896] LOG: [RX FILTER] Raw packet (65 bytes): 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 +[2026-02-20T18:15:58.470919] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.0 +[2026-02-20T18:15:58.470934] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) +[2026-02-20T18:15:58.470950] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:15:58.470962] LOG: [RX FILTER] Channel hash: 0xad +[2026-02-20T18:15:58.470973] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad +[2026-02-20T18:15:58.471115] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash +[2026-02-20T18:15:58.471128] LOG: [RX LOG] Dropped packet hex: 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 +[2026-02-20T18:16:00.947965] LOG: [CONN] Frame received (91 bytes): 88 2e c4 15 03 e8 32 cc 81 c5 f8 81 89 60 a8 2e a8 74 e5 95 56 88 da 43 77 24 26 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 11 22 f1 b2 cc 75 0f c2 67 e9 2c cc cb 97 2b 25 88 be d9 da 65 9d a9 11 6c ca 96 d1 da e9 31 e3 +[2026-02-20T18:16:00.948119] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:00.948150] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:00.948235] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 32 CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 31 E3 +[2026-02-20T18:16:00.948255] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:16:00.948271] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:16:00.948302] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=83 bytes +[2026-02-20T18:16:00.948320] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:16:00.948333] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:00.948343] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:00.948423] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:16:00.948441] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 32 CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 31 E3 +[2026-02-20T18:16:00.948464] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.5 +[2026-02-20T18:16:00.948480] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:16:00.948491] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:16:00.948506] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:16:00.948519] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:16:00.948530] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:16:00.948546] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:16:00.948654] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:16:00.948822] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.35457, -122.50367 [..." +[2026-02-20T18:16:00.948849] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:16:00.948859] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:16:00.948889] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=3 +[2026-02-20T18:16:00.948900] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:16:00.948921] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 +[2026-02-20T18:16:00.948939] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:16:00.948959] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:16:00.948985] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.35815,-122.11296 +[2026-02-20T18:16:00.949004] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:16:00.949029] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35815,-122.11296 (batch tracking: 1 repeaters, rxCount: 28) +[2026-02-20T18:16:00.949052] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:16:00.949078] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.35815,-122.11296 +[2026-02-20T18:16:00.949531] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:16:00.949549] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:16:00.949561] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:16:01.770846] LOG: [GPS SERVICE] Position stream fired: lat=47.35815, lon=-122.11226, accuracy=3.8m +[2026-02-20T18:16:01.770905] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:16:01.770917] LOG: [RX BATCH] Distance check for repeater CC: 53.19m from first observation (threshold=25m) +[2026-02-20T18:16:01.770922] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:16:01.770925] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:16:01.770930] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:16:01.770938] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.35815,-122.11296 +[2026-02-20T18:16:01.770943] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:16:01.770946] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.35815,-122.11296 +[2026-02-20T18:16:01.770955] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 +[2026-02-20T18:16:01.770960] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:16:01.770965] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=3 +[2026-02-20T18:16:01.771033] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:16:01.771037] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:16:02.602989] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:02.651215] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0e 00 00 00 92 23 00 00 +[2026-02-20T18:16:02.651290] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:02.651302] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:06.768095] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11166, accuracy=3.8m +[2026-02-20T18:16:07.573994] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:16:07.574336] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:16:07.574352] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:16:07.575628] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:16:07.602629] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:07.663938] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0e 00 00 00 92 23 00 00 +[2026-02-20T18:16:07.664076] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:07.664098] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:08.146965] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:16:08.147044] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:16:08.147067] LOG: [API] Response (200) in 0.57s: {"success":true,"expires_at":1771640467} +[2026-02-20T18:16:08.147086] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:16:08.147109] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:16:08.147544] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:16:08.147569] LOG: [APP] Upload success: +1 items (total: 54) +[2026-02-20T18:16:08.955576] LOG: [CONN] Frame received (98 bytes): 88 33 c4 15 0c e8 7e 38 75 20 20 20 75 38 7e 1b cc 81 c5 f8 81 89 60 a8 2e a8 74 e5 95 56 88 da 43 77 24 26 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 11 22 f1 b2 cc 75 0f c2 67 e9 2c cc cb 97 2b 25 88 be d9 da 65 9d a9 11 6c ca 96 d1 da e9 +[2026-02-20T18:16:08.955733] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:08.955767] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:08.955851] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 +[2026-02-20T18:16:08.955877] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:16:08.955893] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:16:08.955927] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xe8, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=81 bytes +[2026-02-20T18:16:08.955947] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:16:08.955960] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:08.955970] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:08.956057] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:16:08.956072] LOG: [RX FILTER] Raw packet (95 bytes): 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 +[2026-02-20T18:16:08.956099] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.75 +[2026-02-20T18:16:08.956114] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:16:08.956126] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:16:08.956144] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:16:08.956157] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:16:08.956183] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:16:08.956194] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:16:08.956406] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:16:08.956460] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:16:08.956708] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:16:08.956844] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:16:08.956860] LOG: [RX LOG] Dropped packet hex: 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 +[2026-02-20T18:16:11.777817] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11107, accuracy=3.8m +[2026-02-20T18:16:12.604404] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:12.765197] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 93 23 00 00 +[2026-02-20T18:16:12.765354] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:12.765382] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:13.149130] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:16:16.767411] LOG: [GPS SERVICE] Position stream fired: lat=47.35812, lon=-122.11033, accuracy=3.8m +[2026-02-20T18:16:17.602973] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:17.775029] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 93 23 00 00 +[2026-02-20T18:16:17.775143] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:17.775162] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:21.786466] LOG: [GPS SERVICE] Position stream fired: lat=47.35808, lon=-122.10949, accuracy=3.8m +[2026-02-20T18:16:21.846289] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:16:21.846411] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:16:21.846434] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:16:21.846470] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:16:21.846612] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35808, -122.10949 [0.3w]" +[2026-02-20T18:16:21.846726] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:16:21.846735] LOG: [TX LOG] Payload: "@[MapperBot] 47.35808, -122.10949 [0.3w]" +[2026-02-20T18:16:21.846749] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:16:21.846758] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:16:21.846767] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:16:21.846779] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:16:21.846795] LOG: [CONN] Sending ping: @[MapperBot] 47.35808, -122.10949 [0.3w] +[2026-02-20T18:16:22.031] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:16:22.031052] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:16:22.031055] LOG: [CONN] Received OK response +[2026-02-20T18:16:22.576739] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:16:22.576893] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:16:22.602835] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:22.694884] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:22.695010] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:22.695031] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:23.938428] LOG: [CONN] Frame received (73 bytes): 88 33 c2 15 01 cc 81 d4 11 29 66 7f 4f 30 31 c3 31 89 a7 b8 00 26 03 81 d3 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 a3 d1 db 1c e5 94 17 2e 4c a1 04 04 1d 8f 64 a7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:16:23.938633] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:23.938672] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:23.938739] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:16:23.938760] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:16:23.938771] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:16:23.938807] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-62, payload=67 bytes +[2026-02-20T18:16:23.938821] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:16:23.938835] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:16:23.938847] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-62 +[2026-02-20T18:16:23.938857] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:16:23.938871] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:16:23.938883] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:23.938893] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:23.938909] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:16:25.032816] LOG: [PING] Ping sent successfully +[2026-02-20T18:16:26.771771] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.10834, accuracy=3.8m +[2026-02-20T18:16:26.847870] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:16:27.604391] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:16:27.604594] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:27.737982] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:16:27.738092] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:16:27.738112] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:16:27.738125] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T18:16:27.793156] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 33 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:27.793288] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:27.793308] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:30.034392] LOG: [PING] RX listening window ended +[2026-02-20T18:16:30.034607] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:16:30.034756] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:16:30.034873] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:16:30.034889] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:16:30.034904] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:16:30.034946] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:16:30.034962] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:16:30.035509] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:16:30.764428] LOG: [CONN] Frame received (82 bytes): 88 30 c4 15 0a cc 32 c7 7e 7a 17 7e c7 32 cc 81 d4 11 29 66 7f 4f 30 31 c3 31 89 a7 b8 00 26 03 81 d3 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 a3 d1 db 1c e5 94 17 2e 4c a1 04 04 1d 8f 64 a7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d 37 +[2026-02-20T18:16:30.764595] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:30.764627] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:30.764705] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0A CC 32 C7 7E 7A 17 7E C7 32 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D 37 +[2026-02-20T18:16:30.764727] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:16:30.764738] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:16:30.764767] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes +[2026-02-20T18:16:30.764780] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:16:30.764794] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:30.764805] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:30.764818] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 32 +[2026-02-20T18:16:30.764886] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:16:30.764910] LOG: [RX FILTER] Raw packet (79 bytes): 15 0A CC 32 C7 7E 7A 17 7E C7 32 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D 37 +[2026-02-20T18:16:30.764928] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.0 +[2026-02-20T18:16:30.764943] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:16:30.764954] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:16:30.764964] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:16:30.765044] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:16:30.765057] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:16:30.765069] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:16:30.765164] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:16:30.765358] LOG: [RX FILTER] Decrypted message (58 chars): "Cozmo: @[MapperBot] 47.35808, -122.10949 [0aDss;T}" +[2026-02-20T18:16:30.765384] LOG: [RX FILTER] Printable ratio: 86.2% (threshold: 60.0%) +[2026-02-20T18:16:30.765393] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:16:30.765427] LOG: [RX LOG] Packet heard via underlying hop: 32, SNR=null, path_length=10 (CARpeater stripped) +[2026-02-20T18:16:30.765443] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:16:30.765461] LOG: [RX BATCH] First observation for repeater 32: SNR=null +[2026-02-20T18:16:30.765557] LOG: [RX BATCH] Started 30s timeout timer for repeater 32 +[2026-02-20T18:16:30.765612] LOG: [RX BATCH] Distance check for repeater 32: 0.00m from first observation (threshold=25m) +[2026-02-20T18:16:30.765640] LOG: [APP] Immediate RX observation: repeater=32, snr=null, location=47.35806,-122.10834 +[2026-02-20T18:16:30.765678] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:16:30.765702] LOG: [APP] Created IMMEDIATE RX pin for repeater: 32 at 47.35806,-122.10834 (batch tracking: 1 repeaters, rxCount: 29) +[2026-02-20T18:16:30.765731] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:16:30.765752] LOG: [RX LOG] ✅ Observation kept in batch: repeater=32, snr=null, location=47.35806,-122.10834 +[2026-02-20T18:16:31.791056] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.10710, accuracy=3.8m +[2026-02-20T18:16:31.791098] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:16:31.791120] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:16:31.791130] LOG: [RX BATCH] Distance check for repeater 32: 93.43m from first observation (threshold=25m) +[2026-02-20T18:16:31.791133] LOG: [RX BATCH] Distance threshold met for repeater 32, marking for flush +[2026-02-20T18:16:31.791135] LOG: [RX BATCH] Flushing repeater 32 +[2026-02-20T18:16:31.791141] LOG: [RX BATCH] Cleared timeout timer for repeater 32 +[2026-02-20T18:16:31.791145] LOG: [RX BATCH] Posting repeater 32: snr=null, location=47.35806,-122.10834 +[2026-02-20T18:16:31.791148] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:16:31.791153] LOG: [APP] Finalized RX entry (best SNR): repeater=32, snr=null, location=47.35806,-122.10834 +[2026-02-20T18:16:31.791158] LOG: [APP] RX pin SNR unchanged for repeater=32: batch best null <= pin 0.00 +[2026-02-20T18:16:31.791164] LOG: [APP] Cleared batch tracking for 32: wasPresent=true, remaining=0 +[2026-02-20T18:16:31.791168] LOG: [APP] Added RX log entry: repeater=32, snr=null, pathLen=10 +[2026-02-20T18:16:31.791217] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:16:31.791233] LOG: [RX BATCH] Repeater 32 removed from buffer +[2026-02-20T18:16:31.791237] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:16:32.603073] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:32.774188] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 30 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:32.774316] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:32.774340] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:16:35.036647] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:16:35.036906] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:16:35.036922] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:16:35.036935] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:16:35.037850] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:16:35.803675] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:16:35.803740] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:16:35.803754] LOG: [API] Response (200) in 0.77s: {"success":true,"expires_at":1771640495} +[2026-02-20T18:16:35.803772] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:16:35.803786] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:16:35.804413] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:16:35.804428] LOG: [APP] Upload success: +2 items (total: 56) +[2026-02-20T18:16:36.777282] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.10580, accuracy=3.8m +[2026-02-20T18:16:37.573781] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:16:37.573888] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:16:37.602894] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:37.785177] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:37.785320] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:37.785339] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:40.804759] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:16:41.810217] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.10461, accuracy=3.8m +[2026-02-20T18:16:42.602958] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:42.793661] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:42.793755] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:42.793766] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:46.648717] LOG: [CONN] Frame received (29 bytes): 88 2f c2 05 04 f9 e0 7e cc 43 83 e2 ba 9c 5a b8 8c d8 78 21 da a1 64 23 24 70 be 6f 25 +[2026-02-20T18:16:46.648772] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:46.648811] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:46.648850] LOG: [RX PARSE] RAW Packet (26 bytes): 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 +[2026-02-20T18:16:46.648877] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T18:16:46.648888] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:16:46.648918] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=4, firstHop=0xf9, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=20 bytes +[2026-02-20T18:16:46.648939] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=4 +[2026-02-20T18:16:46.648949] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:46.648958] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:46.648996] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:16:46.649015] LOG: [RX FILTER] Raw packet (26 bytes): 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 +[2026-02-20T18:16:46.649033] LOG: [RX FILTER] Header: 0x05 | PathLength: 4 | SNR: 11.75 +[2026-02-20T18:16:46.649053] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:16:46.649068] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) +[2026-02-20T18:16:46.649219] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:16:46.649238] LOG: [RX LOG] Dropped packet hex: 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 +[2026-02-20T18:16:46.780654] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.10365, accuracy=3.8m +[2026-02-20T18:16:47.604025] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:47.745856] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0f 00 00 00 93 23 00 00 +[2026-02-20T18:16:47.746004] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:47.746029] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:49.035455] LOG: [CONN] Frame received (35 bytes): 88 31 c4 05 0b f9 e0 7e 75 20 20 75 24 7e db cc 43 83 e2 ba 9c 5a b8 8c d8 78 21 da a1 64 23 24 70 be 6f +[2026-02-20T18:16:49.035600] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:16:49.035636] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:16:49.035673] LOG: [RX PARSE] RAW Packet (32 bytes): 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F +[2026-02-20T18:16:49.035684] LOG: [RX PARSE] Header: 0x05, Route type: 1 +[2026-02-20T18:16:49.035698] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:16:49.035725] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=11, firstHop=0xf9, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=19 bytes +[2026-02-20T18:16:49.035740] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=11 +[2026-02-20T18:16:49.035749] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:16:49.035756] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:16:49.035789] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:16:49.035803] LOG: [RX FILTER] Raw packet (32 bytes): 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F +[2026-02-20T18:16:49.035816] LOG: [RX FILTER] Header: 0x05 | PathLength: 11 | SNR: 12.25 +[2026-02-20T18:16:49.035831] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:16:49.035844] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) +[2026-02-20T18:16:49.035882] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:16:49.035896] LOG: [RX LOG] Dropped packet hex: 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F +[2026-02-20T18:16:51.774664] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.10270, accuracy=3.9m +[2026-02-20T18:16:52.573740] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:16:52.573907] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:16:52.605252] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:52.692671] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0f 00 00 00 94 23 00 00 +[2026-02-20T18:16:52.692759] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:52.692770] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:16:56.787903] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.10178, accuracy=3.8m +[2026-02-20T18:16:57.603022] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:16:57.603263] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:16:57.704225] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:16:57.704365] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:16:57.704385] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:16:57.704402] LOG: [CONN] Battery updated: 4069mV (89%) +[2026-02-20T18:16:57.766501] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0f 00 00 00 94 23 00 00 +[2026-02-20T18:16:57.766807] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:16:57.766833] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:00.036417] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:17:00.036564] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:17:00.036585] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:17:00.036624] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:17:00.036666] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35801, -122.10178 [0.3w]" +[2026-02-20T18:17:00.036676] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:17:00.036686] LOG: [TX LOG] Payload: "@[MapperBot] 47.35801, -122.10178 [0.3w]" +[2026-02-20T18:17:00.036697] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:17:00.036708] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:17:00.036722] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:17:00.036731] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:17:00.036759] LOG: [CONN] Sending ping: @[MapperBot] 47.35801, -122.10178 [0.3w] +[2026-02-20T18:17:00.223794] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:17:00.223936] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:17:00.223949] LOG: [CONN] Received OK response +[2026-02-20T18:17:01.544080] LOG: [CONN] Frame received (73 bytes): 88 2f c4 15 01 cc 81 32 1f 4e 91 be a8 4a 50 2b 96 e4 ee c4 5b 0d fd 34 ff ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 ce 86 99 d1 97 94 0b 8f 97 09 5a d1 2a 13 85 21 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:17:01.544123] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:17:01.544148] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:17:01.544192] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 32 1F 4E 91 BE A8 4A 50 2B 96 E4 EE C4 5B 0D FD 34 FF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 CE 86 99 D1 97 94 0B 8F 97 09 5A D1 2A 13 85 21 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:17:01.544207] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:17:01.544213] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:17:01.544246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-60, payload=67 bytes +[2026-02-20T18:17:01.544255] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:17:01.544264] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:17:01.544273] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-60 +[2026-02-20T18:17:01.544280] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:17:01.544290] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:17:01.544371] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:17:01.544383] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:17:01.544389] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:17:01.808741] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.10077, accuracy=4.1m +[2026-02-20T18:17:01.809185] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:17:01.809351] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:17:02.603127] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:02.653089] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:02.653193] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:02.653213] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:17:03.224935] LOG: [PING] Ping sent successfully +[2026-02-20T18:17:05.039877] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:17:06.771396] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09991, accuracy=4.1m +[2026-02-20T18:17:07.573768] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:17:07.573952] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:17:07.602741] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:07.663136] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:07.663231] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:07.663251] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:08.227533] LOG: [PING] RX listening window ended +[2026-02-20T18:17:08.227692] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:17:08.227728] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:17:08.227801] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:17:08.227814] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:17:08.227832] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:17:08.227857] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:17:08.227879] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:17:08.228298] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:17:11.784716] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09903, accuracy=4.3m +[2026-02-20T18:17:12.605286] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:12.731675] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:12.731762] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:12.731775] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:13.229649] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:17:13.229846] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:17:13.229863] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:17:13.783788] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:17:13.783919] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:17:13.783945] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771640533} +[2026-02-20T18:17:13.783963] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:17:13.783990] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:17:13.787558] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:17:13.787584] LOG: [APP] Upload success: +1 items (total: 57) +[2026-02-20T18:17:16.777358] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09806, accuracy=4.3m +[2026-02-20T18:17:17.603085] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:17.653357] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:17.653504] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:17.653524] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:18.788621] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:17:21.768858] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09721, accuracy=4.3m +[2026-02-20T18:17:22.575007] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:17:22.575159] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:17:22.602868] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:22.669085] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:22.669218] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:22.669238] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:26.788239] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09640, accuracy=4.3m +[2026-02-20T18:17:27.602887] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:17:27.603092] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:27.686346] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:17:27.686618] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:17:27.686626] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:17:27.686637] LOG: [CONN] Battery updated: 4069mV (89%) +[2026-02-20T18:17:27.747951] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:27.748025] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:27.748037] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:31.789047] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09537, accuracy=3.9m +[2026-02-20T18:17:32.602641] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:32.750968] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:32.751027] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:32.751033] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:36.783870] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09437, accuracy=3.9m +[2026-02-20T18:17:36.784012] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:17:36.784062] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:17:37.573685] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:17:37.573787] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:17:37.603437] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:37.752869] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2f 0f 00 00 00 94 23 00 00 +[2026-02-20T18:17:37.752912] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:37.752916] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:17:38.228629] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:17:38.228684] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:17:38.228687] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:17:38.228700] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:17:38.228711] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35799, -122.09437 [0.3w]" +[2026-02-20T18:17:38.228712] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:17:38.228714] LOG: [TX LOG] Payload: "@[MapperBot] 47.35799, -122.09437 [0.3w]" +[2026-02-20T18:17:38.228716] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:17:38.228718] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:17:38.228721] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:17:38.228722] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:17:38.228726] LOG: [CONN] Sending ping: @[MapperBot] 47.35799, -122.09437 [0.3w] +[2026-02-20T18:17:38.412150] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:17:38.412179] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:17:38.412182] LOG: [CONN] Received OK response +[2026-02-20T18:17:40.436991] LOG: [CONN] Frame received (73 bytes): 88 31 c7 15 01 cc 81 cb 63 6c 6e 99 34 f4 b1 44 7d 6f 1a 07 3d b8 a7 40 25 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 d1 50 57 ae e4 51 a1 2e 49 be d6 07 d7 cc a1 23 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:17:40.437039] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:17:40.437047] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:17:40.437059] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 CB 63 6C 6E 99 34 F4 B1 44 7D 6F 1A 07 3D B8 A7 40 25 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 D1 50 57 AE E4 51 A1 2E 49 BE D6 07 D7 CC A1 23 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:17:40.437061] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:17:40.437064] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:17:40.437069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=67 bytes +[2026-02-20T18:17:40.437072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:17:40.437074] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:17:40.437076] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 +[2026-02-20T18:17:40.437078] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:17:40.437081] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:17:40.437083] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:17:40.437085] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:17:40.437086] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:17:41.412732] LOG: [PING] Ping sent successfully +[2026-02-20T18:17:41.773094] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09371, accuracy=3.8m +[2026-02-20T18:17:42.602632] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:42.735685] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:17:42.735741] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:42.735746] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:17:43.229598] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:17:46.413648] LOG: [PING] RX listening window ended +[2026-02-20T18:17:46.413688] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:17:46.413699] LOG: [GRAPH] Recorded txFail event at -119dBm +[2026-02-20T18:17:46.413729] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:17:46.413733] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:17:46.413737] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:17:46.413748] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:17:46.413753] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:17:46.414503] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:17:46.763751] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09308, accuracy=3.9m +[2026-02-20T18:17:47.602662] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:47.741449] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:17:47.741517] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:47.741523] LOG: [CONN] Noise floor updated: -117dBm +[2026-02-20T18:17:51.415603] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:17:51.415676] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:17:51.415682] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:17:52.021086] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:17:52.021114] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:17:52.021119] LOG: [API] Response (200) in 0.60s: {"success":true,"expires_at":1771640571} +[2026-02-20T18:17:52.021125] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:17:52.021130] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:17:52.021239] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:17:52.021244] LOG: [APP] Upload success: +1 items (total: 58) +[2026-02-20T18:17:52.108043] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09245, accuracy=4.4m +[2026-02-20T18:17:52.573645] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:17:52.573717] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:17:52.602713] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:52.751362] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:17:52.751417] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:52.751423] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:17:57.021692] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:17:57.111270] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09199, accuracy=4.0m +[2026-02-20T18:17:57.602611] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:17:57.602687] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:17:57.761140] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:17:57.761207] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:17:57.761216] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:17:57.761224] LOG: [CONN] Battery updated: 4069mV (89%) +[2026-02-20T18:17:57.821272] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:17:57.821321] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:17:57.821330] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:02.103415] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.09148, accuracy=4.9m +[2026-02-20T18:18:02.602772] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:02.683784] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:02.683855] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:02.683867] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:07.099972] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.09070, accuracy=5.9m +[2026-02-20T18:18:07.100011] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:18:07.100062] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:18:07.573650] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:18:07.573743] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:18:07.602698] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:07.693747] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:07.693830] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:07.693839] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:11.763731] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.08985, accuracy=5.0m +[2026-02-20T18:18:12.602717] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:12.700962] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:12.701014] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:12.701019] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:16.414742] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:18:16.414779] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:18:16.414789] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:18:16.414806] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:18:16.414825] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35800, -122.08985 [0.3w]" +[2026-02-20T18:18:16.414828] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:18:16.414830] LOG: [TX LOG] Payload: "@[MapperBot] 47.35800, -122.08985 [0.3w]" +[2026-02-20T18:18:16.414836] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:18:16.414840] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:18:16.414843] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:18:16.414847] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:18:16.414852] LOG: [CONN] Sending ping: @[MapperBot] 47.35800, -122.08985 [0.3w] +[2026-02-20T18:18:16.511181] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:18:16.511233] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:18:16.511237] LOG: [CONN] Received OK response +[2026-02-20T18:18:16.802946] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08934, accuracy=4.3m +[2026-02-20T18:18:17.602599] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:17.659394] LOG: [CONN] Frame received (73 bytes): 88 33 c4 15 01 cc 81 3f 6f 96 8c 3f f5 de 7d ff ea 43 7a 25 63 72 fd 29 63 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 8d 1e b9 6e f7 59 22 32 0a 19 af d3 11 30 98 7a 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:18:17.659445] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:17.659457] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:17.659477] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 3F 6F 96 8C 3F F5 DE 7D FF EA 43 7A 25 63 72 FD 29 63 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 8D 1E B9 6E F7 59 22 32 0A 19 AF D3 11 30 98 7A 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:18:17.659481] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:18:17.659485] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:18:17.659496] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=67 bytes +[2026-02-20T18:18:17.659501] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:18:17.659505] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:18:17.659508] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-60 +[2026-02-20T18:18:17.659514] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:18:17.659516] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:18:17.659519] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:17.659523] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:17.659526] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:18:17.681157] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:17.681203] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:17.681209] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:19.511754] LOG: [PING] Ping sent successfully +[2026-02-20T18:18:21.415634] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:18:21.796561] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08919, accuracy=4.0m +[2026-02-20T18:18:22.573594] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:18:22.573657] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:18:22.602588] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:22.691016] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:22.691088] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:22.691097] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:24.512601] LOG: [PING] RX listening window ended +[2026-02-20T18:18:24.512669] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:18:24.512678] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:18:24.512708] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:18:24.512712] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:18:24.512717] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:18:24.512723] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:18:24.512729] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:18:24.512922] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:18:26.787082] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08886, accuracy=12.3m +[2026-02-20T18:18:27.315597] LOG: [CONN] Frame received (131 bytes): 88 31 c5 11 06 13 c7 32 74 7e cc 61 ff 86 b6 67 de 24 8f af 2d 91 48 a0 a8 b4 8f 9b 12 51 68 65 b4 cb 63 e9 43 60 fa 2f b9 08 1d e4 15 99 69 57 c7 55 55 43 f3 d7 0d ab a4 7d 08 80 22 9a a1 29 e1 98 97 1c ed 43 8e ba 31 e0 56 c0 3b 95 d5 5c c9 1a 03 de 29 0c 3f ff 40 f1 87 a9 49 20 4c 07 da 19 99 be db c5 06 59 0f 4a 47 fa ee ef 03 92 46 1a d4 02 72 14 b3 f8 56 61 73 68 6f 6e 2d 47 44 2d 31 +[2026-02-20T18:18:27.315659] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:27.315671] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:27.315699] LOG: [RX PARSE] RAW Packet (128 bytes): 11 06 13 C7 32 74 7E CC 61 FF 86 B6 67 DE 24 8F AF 2D 91 48 A0 A8 B4 8F 9B 12 51 68 65 B4 CB 63 E9 43 60 FA 2F B9 08 1D E4 15 99 69 57 C7 55 55 43 F3 D7 0D AB A4 7D 08 80 22 9A A1 29 E1 98 97 1C ED 43 8E BA 31 E0 56 C0 3B 95 D5 5C C9 1A 03 DE 29 0C 3F FF 40 F1 87 A9 49 20 4C 07 DA 19 99 BE DB C5 06 59 0F 4A 47 FA EE EF 03 92 46 1A D4 02 72 14 B3 F8 56 61 73 68 6F 6E 2D 47 44 2D 31 +[2026-02-20T18:18:27.315705] LOG: [RX PARSE] Header: 0x11, Route type: 1 +[2026-02-20T18:18:27.315708] LOG: [RX PARSE] Path length offset: 1, Path length: 6 +[2026-02-20T18:18:27.315715] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=6, firstHop=0x13, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=120 bytes +[2026-02-20T18:18:27.315720] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=6 +[2026-02-20T18:18:27.315723] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:27.315726] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:27.315751] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:18:27.315753] LOG: [RX FILTER] Raw packet (128 bytes): 11 06 13 C7 32 74 7E CC 61 FF 86 B6 67 DE 24 8F AF 2D 91 48 A0 A8 B4 8F 9B 12 51 68 65 B4 CB 63 E9 43 60 FA 2F B9 08 1D E4 15 99 69 57 C7 55 55 43 F3 D7 0D AB A4 7D 08 80 22 9A A1 29 E1 98 97 1C ED 43 8E BA 31 E0 56 C0 3B 95 D5 5C C9 1A 03 DE 29 0C 3F FF 40 F1 87 A9 49 20 4C 07 DA 19 99 BE DB C5 06 59 0F 4A 47 FA EE EF 03 92 46 1A D4 02 72 14 B3 F8 56 61 73 68 6F 6E 2D 47 44 2D 31 +[2026-02-20T18:18:27.315759] LOG: [RX FILTER] Header: 0x11 | PathLength: 6 | SNR: 12.25 +[2026-02-20T18:18:27.315763] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:18:27.315767] LOG: [RX FILTER] Packet type: ADVERT (0x11) +[2026-02-20T18:18:27.315770] LOG: [RX FILTER] ADVERT flags: 0x92 +[2026-02-20T18:18:27.315772] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes +[2026-02-20T18:18:27.315819] LOG: [RX FILTER] ADVERT name extracted: "Vashon-GD-1" (11 chars) +[2026-02-20T18:18:27.315826] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% +[2026-02-20T18:18:27.315829] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Vashon-GD-1") +[2026-02-20T18:18:27.315837] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=6 +[2026-02-20T18:18:27.315839] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:18:27.315846] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:18:27.315851] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:18:27.315879] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:18:27.315884] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.35801,-122.08886 +[2026-02-20T18:18:27.315891] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:18:27.315897] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35801,-122.08886 (batch tracking: 1 repeaters, rxCount: 30) +[2026-02-20T18:18:27.315904] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:18:27.315910] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.35801,-122.08886 +[2026-02-20T18:18:27.318705] LOG: [CONN] Frame received (148 bytes): 8a 61 ff 86 b6 67 de 24 8f af 2d 91 48 a0 a8 b4 8f 9b 12 51 68 65 b4 cb 63 e9 43 60 fa 2f b9 08 1d 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 61 73 68 6f 6e 2d 47 44 2d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e4 15 99 69 46 1a d4 02 72 14 b3 f8 f1 15 99 69 +[2026-02-20T18:18:27.318729] LOG: [CONN] Response code: 0x8a (138) +[2026-02-20T18:18:27.318734] LOG: [CONN] Unhandled frame: code=138 (0x8a) +[2026-02-20T18:18:27.602660] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:18:27.602772] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:27.672247] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:18:27.672313] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:18:27.672323] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:18:27.672331] LOG: [CONN] Battery updated: 4059mV (88%) +[2026-02-20T18:18:27.731231] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 95 23 00 00 +[2026-02-20T18:18:27.731296] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:27.731307] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:29.513645] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:18:29.513755] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:18:29.513760] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:18:30.073867] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:18:30.073896] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:18:30.073902] LOG: [API] Response (200) in 0.56s: {"success":true,"expires_at":1771640609} +[2026-02-20T18:18:30.073907] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:18:30.073915] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:18:30.074070] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:18:30.074076] LOG: [APP] Upload success: +1 items (total: 59) +[2026-02-20T18:18:31.301535] LOG: [CONN] Frame received (48 bytes): 88 31 c6 15 08 6b 98 64 13 e8 9d 1b cc ca fb bc 36 90 b8 f7 74 56 e3 e0 31 b6 50 e3 df 49 91 f6 d7 10 3b ef f8 86 1f 95 91 2a dd 1b 40 d9 0a e0 +[2026-02-20T18:18:31.301559] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:31.301576] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:31.301592] LOG: [RX PARSE] RAW Packet (45 bytes): 15 08 6B 98 64 13 E8 9D 1B CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A E0 +[2026-02-20T18:18:31.301598] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:18:31.301602] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:18:31.301615] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x6b, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=35 bytes +[2026-02-20T18:18:31.301620] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:18:31.301622] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:31.301627] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:31.301644] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:18:31.301647] LOG: [RX FILTER] Raw packet (45 bytes): 15 08 6B 98 64 13 E8 9D 1B CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A E0 +[2026-02-20T18:18:31.301654] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 +[2026-02-20T18:18:31.301658] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:18:31.301662] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:18:31.301666] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:18:31.301670] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:18:31.301673] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:18:31.301679] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:18:31.301702] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:18:31.301775] LOG: [RX FILTER] Decrypted message (22 chars): " Andrew KI7PXC L1: T" +[2026-02-20T18:18:31.301783] LOG: [RX FILTER] Printable ratio: 90.9% (threshold: 60.0%) +[2026-02-20T18:18:31.301785] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:18:31.301835] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=8 +[2026-02-20T18:18:31.301841] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:18:31.301847] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.25, new=12.25 +[2026-02-20T18:18:31.301882] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:18:31.301888] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=12.25 +[2026-02-20T18:18:31.781263] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08817, accuracy=3.8m +[2026-02-20T18:18:31.781359] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:18:31.781373] LOG: [RX BATCH] Distance check for repeater CC: 52.06m from first observation (threshold=25m) +[2026-02-20T18:18:31.781376] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:18:31.781379] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:18:31.781431] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:18:31.781437] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.35801,-122.08886 +[2026-02-20T18:18:31.781441] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:18:31.781447] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.35801,-122.08886 +[2026-02-20T18:18:31.781453] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:18:31.781462] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:18:31.781465] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=6 +[2026-02-20T18:18:31.781483] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:18:31.781486] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:18:32.602722] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:32.715051] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 0f 00 00 00 96 23 00 00 +[2026-02-20T18:18:32.715129] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:32.715138] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:33.853579] LOG: [CONN] Frame received (52 bytes): 88 31 c5 15 0d 6b 98 64 13 e8 7e 75 20 20 75 53 7e cc ca fb bc 36 90 b8 f7 74 56 e3 e0 31 b6 50 e3 df 49 91 f6 d7 10 3b ef f8 86 1f 95 91 2a dd 1b 40 d9 0a +[2026-02-20T18:18:33.853632] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:33.853642] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:33.853656] LOG: [RX PARSE] RAW Packet (49 bytes): 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A +[2026-02-20T18:18:33.853660] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:18:33.853665] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:18:33.853672] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x6b, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=34 bytes +[2026-02-20T18:18:33.853677] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:18:33.853680] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:33.853682] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:33.853694] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:18:33.853697] LOG: [RX FILTER] Raw packet (49 bytes): 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A +[2026-02-20T18:18:33.853702] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 +[2026-02-20T18:18:33.853706] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:18:33.853709] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:18:33.853712] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:18:33.853716] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:18:33.853719] LOG: [RX FILTER] Encrypted message: 31 bytes +[2026-02-20T18:18:33.853722] LOG: [CRYPTO] Decrypting message (31 bytes) +[2026-02-20T18:18:33.853777] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:18:33.853791] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:18:33.853861] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:18:33.853887] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:18:33.853889] LOG: [RX LOG] Dropped packet hex: 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A +[2026-02-20T18:18:35.074635] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:18:37.110633] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08718, accuracy=3.8m +[2026-02-20T18:18:37.110677] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:18:37.110781] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:18:37.574611] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:18:37.574729] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:18:37.574736] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:18:37.575099] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:18:37.602692] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:37.661273] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 96 23 00 00 +[2026-02-20T18:18:37.661339] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:37.661347] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:37.833840] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:18:37.833872] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:18:37.833877] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771640617} +[2026-02-20T18:18:37.833882] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:18:37.833893] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:18:37.834052] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:18:37.834059] LOG: [APP] Upload success: +1 items (total: 60) +[2026-02-20T18:18:41.780856] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.08625, accuracy=4.0m +[2026-02-20T18:18:42.602645] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:42.671206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 96 23 00 00 +[2026-02-20T18:18:42.671274] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:42.671280] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:42.834733] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:18:42.859899] LOG: [CONN] Frame received (44 bytes): 88 2e c2 15 04 32 5c db cc 05 40 9a 68 cd 0a a6 27 17 33 c9 ec 94 1a 2c fc 05 dd 73 81 82 76 50 00 0d 86 88 36 c3 3b dd 56 af a6 71 +[2026-02-20T18:18:42.859943] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:42.859958] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:42.859971] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 32 5C DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 81 82 76 50 00 0D 86 88 36 C3 3B DD 56 AF A6 71 +[2026-02-20T18:18:42.859976] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:18:42.859978] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:18:42.859990] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x32, lastHop=0xcc, SNR=11.5, RSSI=-62, payload=35 bytes +[2026-02-20T18:18:42.859995] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:18:42.859997] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:42.859999] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:42.860011] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:18:42.860016] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 32 5C DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 81 82 76 50 00 0D 86 88 36 C3 3B DD 56 AF A6 71 +[2026-02-20T18:18:42.860021] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 +[2026-02-20T18:18:42.860027] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:18:42.860030] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:18:42.860034] LOG: [RX FILTER] Channel hash: 0x05 +[2026-02-20T18:18:42.860039] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma +[2026-02-20T18:18:42.860042] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:18:42.860047] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:18:42.860068] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:18:42.860128] LOG: [RX FILTER] Decrypted message (17 chars): "AlanHelTxt : T" +[2026-02-20T18:18:42.860137] LOG: [RX FILTER] Printable ratio: 88.2% (threshold: 60.0%) +[2026-02-20T18:18:42.860139] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:18:42.860149] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=4 +[2026-02-20T18:18:42.860152] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:18:42.860158] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 +[2026-02-20T18:18:42.860161] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:18:42.860168] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:18:42.860174] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.35803,-122.08625 +[2026-02-20T18:18:42.860180] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:18:42.860191] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35803,-122.08625 (batch tracking: 1 repeaters, rxCount: 31) +[2026-02-20T18:18:42.860199] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:18:42.860207] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.35803,-122.08625 +[2026-02-20T18:18:46.809087] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08523, accuracy=3.8m +[2026-02-20T18:18:46.809139] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:18:46.809151] LOG: [RX BATCH] Distance check for repeater CC: 76.76m from first observation (threshold=25m) +[2026-02-20T18:18:46.809154] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:18:46.809157] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:18:46.809165] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:18:46.809170] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.35803,-122.08625 +[2026-02-20T18:18:46.809173] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:18:46.809178] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.35803,-122.08625 +[2026-02-20T18:18:46.809183] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 +[2026-02-20T18:18:46.809190] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:18:46.809195] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=4 +[2026-02-20T18:18:46.809248] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:18:46.809253] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:18:47.603225] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:47.713079] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2e 0f 00 00 00 96 23 00 00 +[2026-02-20T18:18:47.713138] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:47.713149] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:51.791147] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08426, accuracy=4.1m +[2026-02-20T18:18:52.573605] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:18:52.573712] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:18:52.573717] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:18:52.574049] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:18:52.602800] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:52.722360] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2e 0f 00 00 00 96 23 00 00 +[2026-02-20T18:18:52.722430] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:52.722440] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:53.101423] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:18:53.101451] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:18:53.101454] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771640632} +[2026-02-20T18:18:53.101461] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:18:53.101466] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:18:53.101560] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:18:53.101565] LOG: [APP] Upload success: +1 items (total: 61) +[2026-02-20T18:18:54.513649] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:18:54.513719] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:18:54.513724] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:18:54.513742] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:18:54.513758] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35802, -122.08426 [0.3w]" +[2026-02-20T18:18:54.513762] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:18:54.513764] LOG: [TX LOG] Payload: "@[MapperBot] 47.35802, -122.08426 [0.3w]" +[2026-02-20T18:18:54.513768] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:18:54.513772] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:18:54.513775] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:18:54.513777] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:18:54.513785] LOG: [CONN] Sending ping: @[MapperBot] 47.35802, -122.08426 [0.3w] +[2026-02-20T18:18:54.581018] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:18:54.581088] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:18:54.581095] LOG: [CONN] Received OK response +[2026-02-20T18:18:56.368366] LOG: [CONN] Frame received (73 bytes): 88 32 c5 15 01 cc 81 fc a0 36 78 af 7c c5 91 75 14 d3 61 8c c9 4b ea 99 63 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 9c d4 d0 64 82 45 a1 7f cf b8 51 71 13 51 c5 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:18:56.368394] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:18:56.368414] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:18:56.368440] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 FC A0 36 78 AF 7C C5 91 75 14 D3 61 8C C9 4B EA 99 63 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 9C D4 D0 64 82 45 A1 7F CF B8 51 71 13 51 C5 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:18:56.368449] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:18:56.368453] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:18:56.368473] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=67 bytes +[2026-02-20T18:18:56.368478] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:18:56.368482] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:18:56.368489] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-59 +[2026-02-20T18:18:56.368492] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:18:56.368497] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:18:56.368551] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:18:56.368556] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:18:56.368563] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:18:56.772474] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.08325, accuracy=4.6m +[2026-02-20T18:18:57.582052] LOG: [PING] Ping sent successfully +[2026-02-20T18:18:57.602786] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:18:57.602848] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:18:57.761600] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:18:57.761658] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:18:57.761663] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:18:57.761667] LOG: [CONN] Battery updated: 4073mV (89%) +[2026-02-20T18:18:57.826371] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 32 10 00 00 00 96 23 00 00 +[2026-02-20T18:18:57.826416] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:18:57.826421] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:18:58.102684] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:18:59.514643] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:19:00.657398] LOG: [CONN] Frame received (57 bytes): 88 2f c5 15 21 32 3e 9d 0a 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 20 22 1f ab 7e 02 db cc 05 40 9a 68 cd 0a a6 27 17 33 c9 ec 94 1a 2c fc 05 dd 73 +[2026-02-20T18:19:00.657457] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:19:00.657469] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:19:00.657488] LOG: [RX PARSE] RAW Packet (54 bytes): 15 21 32 3E 9D 0A 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 22 1F AB 7E 02 DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 +[2026-02-20T18:19:00.657493] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:19:00.657499] LOG: [RX PARSE] Path length offset: 1, Path length: 33 +[2026-02-20T18:19:00.657513] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0x32, lastHop=0xcc, SNR=11.75, RSSI=-59, payload=19 bytes +[2026-02-20T18:19:00.657519] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 +[2026-02-20T18:19:00.657522] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:19:00.657525] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:19:00.657544] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:19:00.657547] LOG: [RX FILTER] Raw packet (54 bytes): 15 21 32 3E 9D 0A 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 22 1F AB 7E 02 DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 +[2026-02-20T18:19:00.657555] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 11.75 +[2026-02-20T18:19:00.657560] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:19:00.657566] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:19:00.657569] LOG: [RX FILTER] Channel hash: 0x05 +[2026-02-20T18:19:00.657574] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma +[2026-02-20T18:19:00.657580] LOG: [RX FILTER] Encrypted message: 16 bytes +[2026-02-20T18:19:00.657584] LOG: [CRYPTO] Decrypting message (16 bytes) +[2026-02-20T18:19:00.657607] LOG: [CRYPTO] Decrypted successfully (16 bytes) +[2026-02-20T18:19:00.657676] LOG: [RX FILTER] Decrypted message (10 chars): "AlanHelTxt" +[2026-02-20T18:19:00.657684] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:19:00.657687] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:19:00.657752] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=33 +[2026-02-20T18:19:00.657757] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:19:00.657764] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 +[2026-02-20T18:19:00.657772] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:19:00.657782] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:19:00.657789] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.35803,-122.08325 +[2026-02-20T18:19:00.657797] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:19:00.657807] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35803,-122.08325 (batch tracking: 1 repeaters, rxCount: 32) +[2026-02-20T18:19:00.657817] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:19:00.657824] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.35803,-122.08325 +[2026-02-20T18:19:02.112128] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08215, accuracy=4.1m +[2026-02-20T18:19:02.112166] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:19:02.112177] LOG: [RX BATCH] Distance check for repeater CC: 82.98m from first observation (threshold=25m) +[2026-02-20T18:19:02.112180] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:19:02.112183] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:19:02.112188] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:19:02.112192] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.35803,-122.08325 +[2026-02-20T18:19:02.112201] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:19:02.112204] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.35803,-122.08325 +[2026-02-20T18:19:02.112210] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 +[2026-02-20T18:19:02.112216] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:19:02.112222] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=33 +[2026-02-20T18:19:02.112283] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:19:02.112286] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:19:02.582807] LOG: [PING] RX listening window ended +[2026-02-20T18:19:02.582931] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:19:02.582947] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:19:02.582999] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:19:02.583004] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:19:02.583015] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:19:02.583086] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:19:02.583096] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:19:02.592524] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:19:02.605152] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:02.652308] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 10 00 00 00 96 23 00 00 +[2026-02-20T18:19:02.652375] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:02.652386] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:07.101275] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08105, accuracy=4.0m +[2026-02-20T18:19:07.573738] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:19:07.573901] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:19:07.573911] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:19:07.573917] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:19:07.574467] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:19:07.598751] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:19:07.598798] LOG: [API QUEUE] Upload skipped: already uploading +[2026-02-20T18:19:07.606055] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:07.661880] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 10 00 00 00 96 23 00 00 +[2026-02-20T18:19:07.661945] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:07.661954] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:08.094375] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:19:08.094405] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:19:08.094412] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771640647} +[2026-02-20T18:19:08.094417] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:19:08.094425] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:19:08.097820] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:19:08.097843] LOG: [APP] Upload success: +2 items (total: 63) +[2026-02-20T18:19:12.116953] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07998, accuracy=3.8m +[2026-02-20T18:19:12.116995] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:19:12.117050] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:19:12.341693] LOG: [CONN] Frame received (60 bytes): 88 31 c6 15 2b 32 3e 9b 0c 33 cc 6c 82 dc ef 43 ec 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2b e9 24 86 6e 6b ef 55 01 e0 7a 7e cc 05 40 9a 68 cd 0a 2e 27 1f 3b c9 ec +[2026-02-20T18:19:12.341750] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:19:12.341759] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:19:12.341775] LOG: [RX PARSE] RAW Packet (57 bytes): 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC +[2026-02-20T18:19:12.341780] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:19:12.341782] LOG: [RX PARSE] Path length offset: 1, Path length: 43 +[2026-02-20T18:19:12.341795] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=43, firstHop=0x32, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=12 bytes +[2026-02-20T18:19:12.341798] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=43 +[2026-02-20T18:19:12.341800] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:19:12.341804] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:19:12.341818] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:19:12.341821] LOG: [RX FILTER] Raw packet (57 bytes): 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC +[2026-02-20T18:19:12.341825] LOG: [RX FILTER] Header: 0x15 | PathLength: 43 | SNR: 12.25 +[2026-02-20T18:19:12.341829] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:19:12.341832] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:19:12.341835] LOG: [RX FILTER] Channel hash: 0x05 +[2026-02-20T18:19:12.341840] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma +[2026-02-20T18:19:12.341843] LOG: [RX FILTER] Encrypted message: 9 bytes +[2026-02-20T18:19:12.341845] LOG: [CRYPTO] Decrypting message (9 bytes) +[2026-02-20T18:19:12.341891] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:19:12.341907] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:19:12.341971] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:19:12.341996] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:19:12.342001] LOG: [RX LOG] Dropped packet hex: 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC +[2026-02-20T18:19:12.602675] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:12.701936] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:12.701995] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:12.702001] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:13.098660] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:19:17.106227] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.07899, accuracy=3.8m +[2026-02-20T18:19:17.602608] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:17.712996] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:17.713062] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:17.713073] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:22.105470] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.07812, accuracy=3.8m +[2026-02-20T18:19:22.573649] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:19:22.573923] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:19:22.602625] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:22.721835] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:22.721915] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:22.721924] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:27.115507] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.07714, accuracy=3.8m +[2026-02-20T18:19:27.602616] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:19:27.602691] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:27.733502] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:19:27.733659] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:19:27.733670] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:19:27.733683] LOG: [CONN] Battery updated: 4066mV (89%) +[2026-02-20T18:19:27.791206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:27.791267] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:27.791282] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:31.785618] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.07616, accuracy=3.8m +[2026-02-20T18:19:32.583626] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:19:32.583708] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:19:32.583715] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:19:32.583741] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:19:32.583772] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35801, -122.07616 [0.3w]" +[2026-02-20T18:19:32.583779] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:19:32.583783] LOG: [TX LOG] Payload: "@[MapperBot] 47.35801, -122.07616 [0.3w]" +[2026-02-20T18:19:32.583791] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:19:32.583797] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:19:32.583802] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:19:32.583811] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:19:32.583821] LOG: [CONN] Sending ping: @[MapperBot] 47.35801, -122.07616 [0.3w] +[2026-02-20T18:19:32.603505] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:32.651320] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:19:32.651361] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:19:32.651367] LOG: [CONN] Received OK response +[2026-02-20T18:19:32.712543] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:32.712605] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:32.712616] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:34.334865] LOG: [CONN] Frame received (73 bytes): 88 2f c6 15 01 cc 81 a6 ad 40 99 87 83 01 45 97 c6 95 4b 68 4b 6f 22 4b cf ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 4d e6 5d 25 1e f9 43 9f 65 6f ad 50 d2 c2 b1 35 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:19:34.334954] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:19:34.334972] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:19:34.334998] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:19:34.335006] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:19:34.335010] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:19:34.335024] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=67 bytes +[2026-02-20T18:19:34.335030] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:19:34.335036] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:19:34.335042] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-58 +[2026-02-20T18:19:34.335046] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:19:34.335053] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:19:34.335058] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:19:34.335062] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:19:34.335072] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:19:35.651728] LOG: [PING] Ping sent successfully +[2026-02-20T18:19:36.801670] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07511, accuracy=3.8m +[2026-02-20T18:19:37.573622] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:19:37.573710] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:19:37.584587] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:19:37.602802] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:37.691133] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:37.691189] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:37.691196] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:40.653828] LOG: [PING] RX listening window ended +[2026-02-20T18:19:40.653892] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:19:40.653901] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:19:40.653923] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:19:40.653925] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:19:40.653928] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:19:40.653933] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:19:40.653936] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:19:40.654079] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:19:42.114224] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07432, accuracy=3.8m +[2026-02-20T18:19:42.602626] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:42.700811] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:42.700861] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:42.700866] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:45.654923] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:19:45.655106] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:19:45.655123] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:19:45.990009] LOG: [CONN] Frame received (82 bytes): 88 2f ce 15 0c cc db 7e 75 20 20 20 75 7e 02 db cc 81 a6 ad 40 99 87 83 01 45 97 c6 95 4b 68 4b 6f 22 4b cf ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 4d e6 5d 25 1e f9 43 9f 65 6f ad 50 d2 c2 b1 35 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f +[2026-02-20T18:19:45.990100] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:19:45.990118] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:19:45.990153] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F +[2026-02-20T18:19:45.990163] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:19:45.990169] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:19:45.990186] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-50, payload=65 bytes +[2026-02-20T18:19:45.990195] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:19:45.990199] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:19:45.990205] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:19:45.990213] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:19:45.990244] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:19:45.990249] LOG: [RX FILTER] Raw packet (79 bytes): 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F +[2026-02-20T18:19:45.990259] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 +[2026-02-20T18:19:45.990264] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:19:45.990271] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:19:45.990278] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:19:45.990284] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:19:45.990292] LOG: [RX FILTER] Encrypted message: 62 bytes +[2026-02-20T18:19:45.990299] LOG: [CRYPTO] Decrypting message (62 bytes) +[2026-02-20T18:19:45.990402] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:19:45.990429] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:19:45.990636] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:19:45.990765] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:19:45.990774] LOG: [RX LOG] Dropped packet hex: 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F +[2026-02-20T18:19:46.179928] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:19:46.179964] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:19:46.179969] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771640685} +[2026-02-20T18:19:46.179977] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:19:46.179984] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:19:46.180194] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:19:46.180201] LOG: [APP] Upload success: +1 items (total: 64) +[2026-02-20T18:19:46.803150] LOG: [GPS SERVICE] Position stream fired: lat=47.35809, lon=-122.07409, accuracy=4.2m +[2026-02-20T18:19:46.803196] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:19:46.803263] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:19:47.602762] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:47.712575] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:47.712702] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:47.712726] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:51.180737] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:19:52.124801] LOG: [GPS SERVICE] Position stream fired: lat=47.35835, lon=-122.07397, accuracy=24.5m +[2026-02-20T18:19:52.573964] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:19:52.574187] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:19:52.604997] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:52.723912] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:52.724011] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:52.724022] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:19:57.107416] LOG: [GPS SERVICE] Position stream fired: lat=47.35887, lon=-122.07400, accuracy=4.4m +[2026-02-20T18:19:57.603656] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:19:57.603907] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:19:57.733769] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:19:57.733920] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:19:57.733938] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:19:57.733964] LOG: [CONN] Battery updated: 4059mV (88%) +[2026-02-20T18:19:57.792915] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:19:57.793043] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:19:57.793064] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:01.777177] LOG: [GPS SERVICE] Position stream fired: lat=47.35938, lon=-122.07402, accuracy=4.2m +[2026-02-20T18:20:02.602803] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:02.654509] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:20:02.654731] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:02.654748] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:05.447963] LOG: [CONN] Frame received (44 bytes): 88 2f c6 15 04 15 ae 7e cc 11 9d cb 1f fd e7 3c ac 9e 97 81 b4 42 c3 a2 29 8f d1 e3 b5 d7 30 69 2d 6b 4b 26 8d 3d 7d a9 56 22 87 9b +[2026-02-20T18:20:05.448023] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:05.448034] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:05.448050] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 15 AE 7E CC 11 9D CB 1F FD E7 3C AC 9E 97 81 B4 42 C3 A2 29 8F D1 E3 B5 D7 30 69 2D 6B 4B 26 8D 3D 7D A9 56 22 87 9B +[2026-02-20T18:20:05.448054] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:05.448057] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:20:05.448069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=35 bytes +[2026-02-20T18:20:05.448073] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:20:05.448079] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:05.448081] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:05.448093] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:05.448098] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 15 AE 7E CC 11 9D CB 1F FD E7 3C AC 9E 97 81 B4 42 C3 A2 29 8F D1 E3 B5 D7 30 69 2D 6B 4B 26 8D 3D 7D A9 56 22 87 9B +[2026-02-20T18:20:05.448103] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.75 +[2026-02-20T18:20:05.448109] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) +[2026-02-20T18:20:05.448112] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:05.448115] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:20:05.448120] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:20:05.448124] LOG: [RX FILTER] Encrypted message: 32 bytes +[2026-02-20T18:20:05.448127] LOG: [CRYPTO] Decrypting message (32 bytes) +[2026-02-20T18:20:05.448150] LOG: [CRYPTO] Decrypted successfully (32 bytes) +[2026-02-20T18:20:05.448213] LOG: [RX FILTER] Decrypted message (13 chars): "hankest: Test" +[2026-02-20T18:20:05.448223] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) +[2026-02-20T18:20:05.448225] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:20:05.448236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=4 +[2026-02-20T18:20:05.448238] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:20:05.448246] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 +[2026-02-20T18:20:05.448252] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:20:05.448259] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:20:05.448267] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.35938,-122.07402 +[2026-02-20T18:20:05.448273] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:20:05.448281] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35938,-122.07402 (batch tracking: 1 repeaters, rxCount: 33) +[2026-02-20T18:20:05.448294] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:20:05.448302] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.35938,-122.07402 +[2026-02-20T18:20:05.448428] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:20:05.448434] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:20:05.448438] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:20:06.789128] LOG: [GPS SERVICE] Position stream fired: lat=47.35997, lon=-122.07414, accuracy=4.9m +[2026-02-20T18:20:06.789182] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:20:06.789193] LOG: [RX BATCH] Distance check for repeater CC: 65.44m from first observation (threshold=25m) +[2026-02-20T18:20:06.789198] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:20:06.789202] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:20:06.789208] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:20:06.789217] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.35938,-122.07402 +[2026-02-20T18:20:06.789220] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:20:06.789225] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.35938,-122.07402 +[2026-02-20T18:20:06.789233] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 +[2026-02-20T18:20:06.789238] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:20:06.789245] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=4 +[2026-02-20T18:20:06.789303] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:20:06.789307] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:20:07.576403] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:20:07.576506] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:20:07.576525] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:20:07.577135] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:20:07.602631] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:07.752358] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 +[2026-02-20T18:20:07.752411] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:07.752417] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:08.163554] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:20:08.163580] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:20:08.163586] LOG: [API] Response (200) in 0.59s: {"success":true,"expires_at":1771640707} +[2026-02-20T18:20:08.163591] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:20:08.163598] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:20:08.163705] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:20:08.163711] LOG: [APP] Upload success: +1 items (total: 65) +[2026-02-20T18:20:10.656646] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:20:10.656725] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:20:10.656731] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:20:10.656748] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:20:10.656766] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35997, -122.07414 [0.3w]" +[2026-02-20T18:20:10.656770] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:20:10.656774] LOG: [TX LOG] Payload: "@[MapperBot] 47.35997, -122.07414 [0.3w]" +[2026-02-20T18:20:10.656778] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:20:10.656782] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:20:10.656789] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:20:10.656791] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:20:10.656799] LOG: [CONN] Sending ping: @[MapperBot] 47.35997, -122.07414 [0.3w] +[2026-02-20T18:20:10.840806] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:20:10.840869] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:20:10.840873] LOG: [CONN] Received OK response +[2026-02-20T18:20:11.799900] LOG: [GPS SERVICE] Position stream fired: lat=47.36040, lon=-122.07456, accuracy=4.1m +[2026-02-20T18:20:12.137792] LOG: [CONN] Frame received (73 bytes): 88 32 c7 15 01 cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:20:12.137869] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:12.137884] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:12.137904] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:20:12.137909] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:12.137912] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:20:12.137928] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes +[2026-02-20T18:20:12.137932] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:20:12.137937] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:20:12.137940] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-57 +[2026-02-20T18:20:12.137943] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:20:12.137948] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:20:12.137951] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:12.137955] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:12.137960] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:20:12.603632] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:12.795943] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 +[2026-02-20T18:20:12.796076] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:12.796098] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:13.164748] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:20:13.812311] LOG: [PING] Ping sent successfully +[2026-02-20T18:20:15.658486] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:20:17.118678] LOG: [GPS SERVICE] Position stream fired: lat=47.36073, lon=-122.07520, accuracy=3.8m +[2026-02-20T18:20:17.118725] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:20:17.118806] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:20:17.606006] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:17.656581] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 +[2026-02-20T18:20:17.656705] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:17.656724] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:18.812966] LOG: [PING] RX listening window ended +[2026-02-20T18:20:18.813123] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:20:18.813165] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:20:18.813265] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:20:18.813280] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:20:18.813292] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:20:18.813323] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:20:18.813340] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:20:18.813789] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:20:21.786129] LOG: [GPS SERVICE] Position stream fired: lat=47.36110, lon=-122.07562, accuracy=3.8m +[2026-02-20T18:20:22.574744] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:20:22.574972] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:20:22.574993] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:20:22.603033] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:22.664535] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 +[2026-02-20T18:20:22.664611] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:22.664623] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:22.726391] LOG: [CONN] Frame received (83 bytes): 88 2e bb 15 0c cc db 6c 24 c5 75 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d +[2026-02-20T18:20:22.726692] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:22.726718] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:22.726767] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:20:22.726777] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:22.726787] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:20:22.726806] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-69, payload=66 bytes +[2026-02-20T18:20:22.726818] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:20:22.726824] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:22.726830] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:22.726841] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:20:22.726885] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:22.726891] LOG: [RX FILTER] Raw packet (80 bytes): 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:20:22.726907] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.5 +[2026-02-20T18:20:22.726912] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:20:22.726922] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:22.726930] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:20:22.726937] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:20:22.726948] LOG: [RX FILTER] Encrypted message: 63 bytes +[2026-02-20T18:20:22.726955] LOG: [CRYPTO] Decrypting message (63 bytes) +[2026-02-20T18:20:22.727077] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:22.727120] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:22.727272] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:20:22.727347] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:20:22.727354] LOG: [RX LOG] Dropped packet hex: 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D +[2026-02-20T18:20:23.224661] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:20:23.224728] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:20:23.224746] LOG: [API] Response (200) in 0.65s: {"success":true,"expires_at":1771640722} +[2026-02-20T18:20:23.224759] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:20:23.224777] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:20:23.225199] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:20:23.225220] LOG: [APP] Upload success: +1 items (total: 66) +[2026-02-20T18:20:23.815160] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:20:23.815332] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:20:26.781699] LOG: [GPS SERVICE] Position stream fired: lat=47.36157, lon=-122.07578, accuracy=3.8m +[2026-02-20T18:20:26.804844] LOG: [CONN] Frame received (83 bytes): 88 2d c4 15 12 cc db 6c 24 c5 75 20 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 +[2026-02-20T18:20:26.804920] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:26.804939] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:26.804978] LOG: [RX PARSE] RAW Packet (80 bytes): 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 +[2026-02-20T18:20:26.804989] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:26.804995] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:20:26.805009] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xcc, lastHop=0xcc, SNR=11.25, RSSI=-60, payload=60 bytes +[2026-02-20T18:20:26.805019] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 +[2026-02-20T18:20:26.805025] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:26.805033] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:26.805039] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:20:26.805079] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:26.805086] LOG: [RX FILTER] Raw packet (80 bytes): 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 +[2026-02-20T18:20:26.805099] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 11.25 +[2026-02-20T18:20:26.805104] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:20:26.805112] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:26.805117] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:20:26.805123] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:20:26.805131] LOG: [RX FILTER] Encrypted message: 57 bytes +[2026-02-20T18:20:26.805137] LOG: [CRYPTO] Decrypting message (57 bytes) +[2026-02-20T18:20:26.805237] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:26.805262] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:26.805378] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:20:26.805440] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:20:26.805446] LOG: [RX LOG] Dropped packet hex: 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 +[2026-02-20T18:20:27.602788] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:20:27.602980] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:27.793028] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:20:27.793158] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:20:27.793172] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:20:27.793183] LOG: [CONN] Battery updated: 4069mV (89%) +[2026-02-20T18:20:27.853440] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff 81 d4 10 00 00 00 98 23 00 00 +[2026-02-20T18:20:27.853578] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:27.853597] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:20:28.225667] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:20:29.283362] LOG: [CONN] Frame received (83 bytes): 88 31 c7 15 11 cc db 6c 24 c5 75 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 +[2026-02-20T18:20:29.283542] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:29.283573] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:29.283657] LOG: [RX PARSE] RAW Packet (80 bytes): 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 +[2026-02-20T18:20:29.283674] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:29.283690] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T18:20:29.283761] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=61 bytes +[2026-02-20T18:20:29.283775] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T18:20:29.283802] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:29.283811] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:29.283823] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:20:29.283900] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:29.283912] LOG: [RX FILTER] Raw packet (80 bytes): 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 +[2026-02-20T18:20:29.283935] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 12.25 +[2026-02-20T18:20:29.283946] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:20:29.283957] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:29.283972] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:20:29.283985] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:20:29.283997] LOG: [RX FILTER] Encrypted message: 58 bytes +[2026-02-20T18:20:29.284012] LOG: [CRYPTO] Decrypting message (58 bytes) +[2026-02-20T18:20:29.284193] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:29.284246] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:29.284479] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:20:29.284632] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:20:29.284644] LOG: [RX LOG] Dropped packet hex: 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 +[2026-02-20T18:20:31.738325] LOG: [CONN] Frame received (83 bytes): 88 34 c7 15 19 cc db 6c 24 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 +[2026-02-20T18:20:31.738349] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:31.738366] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:31.738387] LOG: [RX PARSE] RAW Packet (80 bytes): 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 +[2026-02-20T18:20:31.738396] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:31.738401] LOG: [RX PARSE] Path length offset: 1, Path length: 25 +[2026-02-20T18:20:31.738412] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=25, firstHop=0xcc, lastHop=0xcc, SNR=13.0, RSSI=-57, payload=53 bytes +[2026-02-20T18:20:31.738418] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=25 +[2026-02-20T18:20:31.738420] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:31.738423] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:31.738429] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB +[2026-02-20T18:20:31.738449] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:31.738452] LOG: [RX FILTER] Raw packet (80 bytes): 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 +[2026-02-20T18:20:31.738459] LOG: [RX FILTER] Header: 0x15 | PathLength: 25 | SNR: 13.0 +[2026-02-20T18:20:31.738462] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:20:31.738466] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:31.738471] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:20:31.738475] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:20:31.738480] LOG: [RX FILTER] Encrypted message: 50 bytes +[2026-02-20T18:20:31.738484] LOG: [CRYPTO] Decrypting message (50 bytes) +[2026-02-20T18:20:31.738581] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:31.738638] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:20:31.738717] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:20:31.738755] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:20:31.738758] LOG: [RX LOG] Dropped packet hex: 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 +[2026-02-20T18:20:31.789432] LOG: [GPS SERVICE] Position stream fired: lat=47.36194, lon=-122.07583, accuracy=4.2m +[2026-02-20T18:20:32.602929] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:32.683251] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 +[2026-02-20T18:20:32.683382] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:32.683402] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:36.782466] LOG: [GPS SERVICE] Position stream fired: lat=47.36211, lon=-122.07588, accuracy=4.0m +[2026-02-20T18:20:37.573806] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:20:37.573979] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:20:37.605467] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:37.693364] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 +[2026-02-20T18:20:37.693502] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:37.693528] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:41.795619] LOG: [GPS SERVICE] Position stream fired: lat=47.36248, lon=-122.07627, accuracy=4.1m +[2026-02-20T18:20:42.603046] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:42.703857] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 +[2026-02-20T18:20:42.704004] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:42.704026] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:46.786512] LOG: [GPS SERVICE] Position stream fired: lat=47.36286, lon=-122.07671, accuracy=4.0m +[2026-02-20T18:20:47.603085] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:47.713741] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 +[2026-02-20T18:20:47.713891] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:47.713914] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:48.825060] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:20:48.825223] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:20:48.825252] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:20:48.825296] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:20:48.825346] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36286, -122.07671 [0.3w]" +[2026-02-20T18:20:48.825358] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:20:48.825367] LOG: [TX LOG] Payload: "@[MapperBot] 47.36286, -122.07671 [0.3w]" +[2026-02-20T18:20:48.825386] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:20:48.825399] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:20:48.825416] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:20:48.825428] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:20:48.825449] LOG: [CONN] Sending ping: @[MapperBot] 47.36286, -122.07671 [0.3w] +[2026-02-20T18:20:48.975177] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:20:48.975305] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:20:48.975333] LOG: [CONN] Received OK response +[2026-02-20T18:20:49.818766] LOG: [CONN] Frame received (73 bytes): 88 2b b7 15 01 cc 81 20 2c cd da 5b 0f a1 8f ef 4d 83 92 cd 75 db de e1 7f 44 96 6d c4 a7 68 a6 1d 8f 43 53 aa 5d 04 43 8b 87 b4 82 33 11 57 1b 8f e5 23 d7 33 4f a0 9b 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:20:49.818913] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:49.818943] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:49.819016] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 20 2C CD DA 5B 0F A1 8F EF 4D 83 92 CD 75 DB DE E1 7F 44 96 6D C4 A7 68 A6 1D 8F 43 53 AA 5D 04 43 8B 87 B4 82 33 11 57 1B 8F E5 23 D7 33 4F A0 9B 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:20:49.819039] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:49.819050] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:20:49.819085] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=10.75, RSSI=-73, payload=67 bytes +[2026-02-20T18:20:49.819101] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:20:49.819111] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:20:49.819136] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-73 +[2026-02-20T18:20:49.819147] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:20:49.819156] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:20:49.819173] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:49.819183] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:49.819193] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:20:51.802167] LOG: [GPS SERVICE] Position stream fired: lat=47.36333, lon=-122.07693, accuracy=4.0m +[2026-02-20T18:20:51.802213] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:20:51.802278] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:20:51.980132] LOG: [PING] Ping sent successfully +[2026-02-20T18:20:52.573664] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:20:52.573777] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:20:52.602748] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:52.722887] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b7 2b 11 00 00 00 99 23 00 00 +[2026-02-20T18:20:52.723018] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:52.723037] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:20:53.826732] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:20:56.980668] LOG: [PING] RX listening window ended +[2026-02-20T18:20:56.980713] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:20:56.980734] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:20:56.980766] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:20:56.980772] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:20:56.980779] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:20:56.980792] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:20:56.980798] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:20:56.981333] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:20:57.114277] LOG: [GPS SERVICE] Position stream fired: lat=47.36382, lon=-122.07693, accuracy=3.8m +[2026-02-20T18:20:57.604893] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:20:57.605092] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:20:57.763813] LOG: [CONN] Frame received (11 bytes): 0c d7 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:20:57.763905] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:20:57.763916] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:20:57.763928] LOG: [CONN] Battery updated: 4055mV (88%) +[2026-02-20T18:20:57.796097] LOG: [CONN] Frame received (82 bytes): 88 31 c2 15 0a 08 26 f8 6a 9a aa cd 7a 7e cc 11 a3 b9 84 a9 75 a7 52 54 7a 6a 9b 16 7f 20 e2 d2 6a d6 01 9c a6 3c 42 62 0d 26 25 87 bc c0 e7 74 64 02 b8 7c ad b3 71 84 7b a8 04 24 76 28 58 1a 5e f1 7b 4c 97 d2 14 00 21 92 e5 fa e3 4c 80 bd 25 22 +[2026-02-20T18:20:57.796199] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:20:57.796224] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:20:57.796282] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0A 08 26 F8 6A 9A AA CD 7A 7E CC 11 A3 B9 84 A9 75 A7 52 54 7A 6A 9B 16 7F 20 E2 D2 6A D6 01 9C A6 3C 42 62 0D 26 25 87 BC C0 E7 74 64 02 B8 7C AD B3 71 84 7B A8 04 24 76 28 58 1A 5E F1 7B 4C 97 D2 14 00 21 92 E5 FA E3 4C 80 BD 25 22 +[2026-02-20T18:20:57.796299] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:20:57.796307] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:20:57.796329] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x08, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=67 bytes +[2026-02-20T18:20:57.796341] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:20:57.796349] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:20:57.796366] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:20:57.796421] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:20:57.796430] LOG: [RX FILTER] Raw packet (79 bytes): 15 0A 08 26 F8 6A 9A AA CD 7A 7E CC 11 A3 B9 84 A9 75 A7 52 54 7A 6A 9B 16 7F 20 E2 D2 6A D6 01 9C A6 3C 42 62 0D 26 25 87 BC C0 E7 74 64 02 B8 7C AD B3 71 84 7B A8 04 24 76 28 58 1A 5E F1 7B 4C 97 D2 14 00 21 92 E5 FA E3 4C 80 BD 25 22 +[2026-02-20T18:20:57.796447] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 +[2026-02-20T18:20:57.796456] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:20:57.796462] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:20:57.796473] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:20:57.796481] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:20:57.796488] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:20:57.796500] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:20:57.796559] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:20:57.796684] LOG: [RX FILTER] Decrypted message (45 chars): "Dude: @[hankest] heard 7 hops on bellingham" +[2026-02-20T18:20:57.796701] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) +[2026-02-20T18:20:57.796713] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:20:57.796734] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=10 +[2026-02-20T18:20:57.796749] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:20:57.796760] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:20:57.796778] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:20:57.796796] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:20:57.796811] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36382,-122.07693 +[2026-02-20T18:20:57.796828] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:20:57.796844] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36382,-122.07693 (batch tracking: 1 repeaters, rxCount: 34) +[2026-02-20T18:20:57.796863] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:20:57.796878] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36382,-122.07693 +[2026-02-20T18:20:57.797229] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:20:57.797239] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:20:57.797247] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:20:57.798140] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 31 11 00 00 00 9a 23 00 00 +[2026-02-20T18:20:57.798155] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:20:57.798167] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:01.783836] LOG: [GPS SERVICE] Position stream fired: lat=47.36427, lon=-122.07690, accuracy=3.9m +[2026-02-20T18:21:01.783897] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:21:01.783909] LOG: [RX BATCH] Distance check for repeater CC: 49.88m from first observation (threshold=25m) +[2026-02-20T18:21:01.783913] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:21:01.783918] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:21:01.783925] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:21:01.783933] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36382,-122.07693 +[2026-02-20T18:21:01.783938] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:01.783943] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36382,-122.07693 +[2026-02-20T18:21:01.783953] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:21:01.783958] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:21:01.783965] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=10 +[2026-02-20T18:21:01.784043] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:21:01.784048] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:21:01.981588] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:21:01.981687] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:21:01.981694] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:21:01.981699] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:21:01.982038] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:21:02.433578] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:21:02.433670] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:21:02.433688] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771640762} +[2026-02-20T18:21:02.433713] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:21:02.433731] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:21:02.434506] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:21:02.434556] LOG: [APP] Upload success: +2 items (total: 68) +[2026-02-20T18:21:02.602855] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:02.711143] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 31 11 00 00 00 9a 23 00 00 +[2026-02-20T18:21:02.711214] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:02.711223] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:05.999469] LOG: [CONN] Frame received (144 bytes): 88 30 be 15 0e 01 e0 7e 75 20 20 20 20 20 20 20 53 7e cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 29 e0 dd c8 +[2026-02-20T18:21:05.999542] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:05.999557] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:05.999597] LOG: [RX PARSE] RAW Packet (141 bytes): 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 +[2026-02-20T18:21:05.999607] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:05.999613] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:21:05.999627] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x01, lastHop=0xcc, SNR=12.0, RSSI=-66, payload=125 bytes +[2026-02-20T18:21:05.999634] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:21:05.999640] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:05.999643] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:05.999687] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:05.999691] LOG: [RX FILTER] Raw packet (141 bytes): 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 +[2026-02-20T18:21:05.999700] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.0 +[2026-02-20T18:21:05.999705] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) +[2026-02-20T18:21:05.999711] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:05.999714] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:21:05.999718] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:21:05.999725] LOG: [RX FILTER] Encrypted message: 122 bytes +[2026-02-20T18:21:05.999729] LOG: [CRYPTO] Decrypting message (122 bytes) +[2026-02-20T18:21:05.999873] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:05.999895] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:05.999995] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:06.000052] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:06.000059] LOG: [RX LOG] Dropped packet hex: 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 +[2026-02-20T18:21:06.795053] LOG: [GPS SERVICE] Position stream fired: lat=47.36459, lon=-122.07667, accuracy=3.8m +[2026-02-20T18:21:07.435724] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:21:07.574113] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:21:07.574222] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:21:07.603007] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:07.693634] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 30 11 00 00 00 9a 23 00 00 +[2026-02-20T18:21:07.693766] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:07.693785] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:11.788957] LOG: [GPS SERVICE] Position stream fired: lat=47.36479, lon=-122.07607, accuracy=3.8m +[2026-02-20T18:21:12.602800] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:12.704006] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff 89 fc 11 00 00 00 9a 23 00 00 +[2026-02-20T18:21:12.704110] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:12.704123] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:21:13.749543] LOG: [CONN] Frame received (146 bytes): 88 2f c8 15 11 01 e0 7e 75 20 20 20 20 20 20 20 20 53 7e ef db cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 29 e0 dd +[2026-02-20T18:21:13.749676] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:13.749704] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:13.749792] LOG: [RX PARSE] RAW Packet (143 bytes): 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD +[2026-02-20T18:21:13.749818] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:13.749831] LOG: [RX PARSE] Path length offset: 1, Path length: 17 +[2026-02-20T18:21:13.749858] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0x01, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=124 bytes +[2026-02-20T18:21:13.749872] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 +[2026-02-20T18:21:13.749881] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:13.749889] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:13.749980] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:13.749989] LOG: [RX FILTER] Raw packet (143 bytes): 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD +[2026-02-20T18:21:13.750008] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 11.75 +[2026-02-20T18:21:13.750020] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:21:13.750033] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:13.750042] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:21:13.750052] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:21:13.750071] LOG: [RX FILTER] Encrypted message: 121 bytes +[2026-02-20T18:21:13.750079] LOG: [CRYPTO] Decrypting message (121 bytes) +[2026-02-20T18:21:13.750268] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:13.750309] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:13.750507] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:13.750714] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:13.750720] LOG: [RX LOG] Dropped packet hex: 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD +[2026-02-20T18:21:16.009994] LOG: [GPS SERVICE] Position stream fired: lat=47.36505, lon=-122.07545, accuracy=3.8m +[2026-02-20T18:21:16.339458] LOG: [CONN] Frame received (148 bytes): 88 f8 87 15 15 01 e0 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e db ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 e0 +[2026-02-20T18:21:16.339502] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:16.339534] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:16.339606] LOG: [RX PARSE] RAW Packet (145 bytes): 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:16.339627] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:16.339638] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:21:16.339661] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x01, lastHop=0xdb, SNR=-2.0, RSSI=-121, payload=122 bytes +[2026-02-20T18:21:16.339673] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:21:16.339680] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:16.339685] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:16.339760] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:16.339768] LOG: [RX FILTER] Raw packet (145 bytes): 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:16.339787] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: -2.0 +[2026-02-20T18:21:16.339799] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) +[2026-02-20T18:21:16.339807] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:16.339813] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:21:16.339822] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:21:16.339830] LOG: [RX FILTER] Encrypted message: 119 bytes +[2026-02-20T18:21:16.339837] LOG: [CRYPTO] Decrypting message (119 bytes) +[2026-02-20T18:21:16.339985] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:16.340100] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:16.340258] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:16.340357] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:16.340368] LOG: [RX LOG] Dropped packet hex: 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:17.603810] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:17.741045] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 87 f8 11 00 00 00 9b 23 00 00 +[2026-02-20T18:21:17.741114] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:17.741121] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:19.593134] LOG: [CONN] Frame received (149 bytes): 88 31 c5 15 16 01 e0 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e db cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 e0 +[2026-02-20T18:21:19.593300] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:19.593329] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:19.593456] LOG: [RX PARSE] RAW Packet (146 bytes): 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:19.593491] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:19.593503] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T18:21:19.593532] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x01, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=122 bytes +[2026-02-20T18:21:19.593551] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T18:21:19.593561] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:19.593574] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:19.593692] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:19.593704] LOG: [RX FILTER] Raw packet (146 bytes): 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:19.593733] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 12.25 +[2026-02-20T18:21:19.593751] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:21:19.593762] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:19.593772] LOG: [RX FILTER] Channel hash: 0xca +[2026-02-20T18:21:19.593789] LOG: [RX FILTER] ✓ Channel matched: #bot +[2026-02-20T18:21:19.593800] LOG: [RX FILTER] Encrypted message: 119 bytes +[2026-02-20T18:21:19.593815] LOG: [CRYPTO] Decrypting message (119 bytes) +[2026-02-20T18:21:19.594028] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:19.594084] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:19.594299] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:19.594474] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:19.594490] LOG: [RX LOG] Dropped packet hex: 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 +[2026-02-20T18:21:22.573819] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:21:22.573941] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:21:22.605415] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:22.783450] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 11 00 00 00 9b 23 00 00 +[2026-02-20T18:21:22.783592] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:22.783617] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:23.010322] LOG: [GPS SERVICE] Position stream fired: lat=47.36569, lon=-122.07524, accuracy=3.8m +[2026-02-20T18:21:23.010421] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:21:23.010448] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:21:23.191410] LOG: [CONN] Frame received (101 bytes): 88 f3 87 15 0d c7 32 75 62 54 1e 29 1f 5a 15 e0 86 db 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 56 +[2026-02-20T18:21:23.191516] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:23.191534] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:23.191582] LOG: [RX PARSE] RAW Packet (98 bytes): 15 0D C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 +[2026-02-20T18:21:23.191594] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:23.191599] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:21:23.191620] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xc7, lastHop=0xdb, SNR=-3.25, RSSI=-121, payload=83 bytes +[2026-02-20T18:21:23.191626] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:21:23.191631] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:23.191638] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:23.191682] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:23.191689] LOG: [RX FILTER] Raw packet (98 bytes): 15 0D C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 +[2026-02-20T18:21:23.191700] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: -3.25 +[2026-02-20T18:21:23.191710] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) +[2026-02-20T18:21:23.191714] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:23.191719] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:23.191727] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:23.191734] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:23.191739] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:23.191797] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:23.191922] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34248, -122.52344 [..." +[2026-02-20T18:21:23.191935] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:23.191939] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:23.191958] LOG: [RX LOG] Packet heard via last hop: DB, SNR=-3.25, path_length=13 +[2026-02-20T18:21:23.191966] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:23.191976] LOG: [RX BATCH] First observation for repeater DB: SNR=-3.25 +[2026-02-20T18:21:23.191986] LOG: [RX BATCH] Started 30s timeout timer for repeater DB +[2026-02-20T18:21:23.192002] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:23.192013] LOG: [APP] Immediate RX observation: repeater=DB, snr=-3.25, location=47.36569,-122.07524 +[2026-02-20T18:21:23.192026] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:21:23.192037] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36569,-122.07524 (batch tracking: 1 repeaters, rxCount: 35) +[2026-02-20T18:21:23.192050] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:23.192060] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=-3.25, location=47.36569,-122.07524 +[2026-02-20T18:21:23.192271] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:21:23.192277] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:21:23.192281] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:21:24.620233] LOG: [CONN] Frame received (102 bytes): 88 31 c0 15 0e c7 32 75 62 54 1e 29 1f 5a 15 e0 86 db cc 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 56 +[2026-02-20T18:21:24.620365] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:24.620389] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:24.620449] LOG: [RX PARSE] RAW Packet (99 bytes): 15 0E C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 +[2026-02-20T18:21:24.620463] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:24.620475] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:21:24.620492] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xc7, lastHop=0xcc, SNR=12.25, RSSI=-64, payload=83 bytes +[2026-02-20T18:21:24.620505] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:21:24.620514] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:24.620520] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:24.620578] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:24.620586] LOG: [RX FILTER] Raw packet (99 bytes): 15 0E C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 +[2026-02-20T18:21:24.620602] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.25 +[2026-02-20T18:21:24.620611] LOG: [RX FILTER] ✓ RSSI OK (-64 < -30) +[2026-02-20T18:21:24.620622] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:24.620631] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:24.620638] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:24.620649] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:24.620657] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:24.620728] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:24.620860] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34248, -122.52344 [..." +[2026-02-20T18:21:24.620881] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:24.620887] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:24.620911] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=14 +[2026-02-20T18:21:24.620917] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:24.620932] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 +[2026-02-20T18:21:24.620944] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:21:24.620959] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:24.620977] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36569,-122.07524 +[2026-02-20T18:21:24.620989] LOG: [APP] Current batch tracking: 1 repeaters: {DB} +[2026-02-20T18:21:24.621007] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36569,-122.07524 (batch tracking: 2 repeaters, rxCount: 36) +[2026-02-20T18:21:24.621022] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:24.621039] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36569,-122.07524 +[2026-02-20T18:21:26.042733] LOG: [CONN] Frame received (108 bytes): 88 04 8b 15 15 c7 32 75 62 54 1e 29 1f 5a 15 e0 53 e3 07 7e 75 20 20 53 7a db 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 +[2026-02-20T18:21:26.042844] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:26.042870] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:26.042945] LOG: [RX PARSE] RAW Packet (105 bytes): 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:26.042964] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:26.042975] LOG: [RX PARSE] Path length offset: 1, Path length: 21 +[2026-02-20T18:21:26.043] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xc7, lastHop=0xdb, SNR=1.0, RSSI=-117, payload=82 bytes +[2026-02-20T18:21:26.043011] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 +[2026-02-20T18:21:26.043024] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:26.043033] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:26.043101] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:26.043110] LOG: [RX FILTER] Raw packet (105 bytes): 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:26.043128] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 1.0 +[2026-02-20T18:21:26.043139] LOG: [RX FILTER] ✓ RSSI OK (-117 < -30) +[2026-02-20T18:21:26.043151] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:26.043160] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:26.043169] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:26.043181] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:21:26.043190] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:21:26.043329] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:26.043365] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:26.043522] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:26.043631] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:26.043641] LOG: [RX LOG] Dropped packet hex: 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:26.983430] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:21:26.983511] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:21:26.983528] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:21:26.983579] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:21:26.983625] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36569, -122.07524 [0.3w]" +[2026-02-20T18:21:26.983641] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:21:26.983651] LOG: [TX LOG] Payload: "@[MapperBot] 47.36569, -122.07524 [0.3w]" +[2026-02-20T18:21:26.983664] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:21:26.983683] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:21:26.983695] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:21:26.983706] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:21:26.983734] LOG: [CONN] Sending ping: @[MapperBot] 47.36569, -122.07524 [0.3w] +[2026-02-20T18:21:27.018156] LOG: [CONN] Frame received (109 bytes): 88 2c c2 15 16 c7 32 75 62 54 1e 29 1f 5a 15 e0 53 e3 07 7e 75 20 20 53 7a db cc 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 +[2026-02-20T18:21:27.018223] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:27.018234] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:27.018263] LOG: [RX PARSE] RAW Packet (106 bytes): 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:27.018270] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:27.018273] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T18:21:27.018286] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xc7, lastHop=0xcc, SNR=11.0, RSSI=-62, payload=82 bytes +[2026-02-20T18:21:27.018291] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T18:21:27.018294] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:21:27.018300] LOG: [TX LOG] Processing rx_log entry: SNR=11.0, RSSI=-62 +[2026-02-20T18:21:27.018303] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:21:27.018309] LOG: [TX LOG] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:21:27.018312] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:21:27.018315] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:21:27.018320] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:21:27.018324] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:21:27.018391] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:27.018402] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:27.018408] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:27.018411] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:27.018436] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:27.018439] LOG: [RX FILTER] Raw packet (106 bytes): 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:27.018446] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 11.0 +[2026-02-20T18:21:27.018450] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) +[2026-02-20T18:21:27.018454] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:27.018458] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:27.018461] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:27.018466] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:21:27.018470] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:21:27.018511] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:27.018543] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:27.018587] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) + + +[2026-02-20T18:21:27.018619] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:27.018622] LOG: [RX LOG] Dropped packet hex: 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 +[2026-02-20T18:21:27.042111] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:21:27.042245] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:21:27.042265] LOG: [CONN] Received OK response +[2026-02-20T18:21:27.603161] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:21:27.603435] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:27.709057] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:21:27.709214] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:21:27.709233] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:21:27.709256] LOG: [CONN] Battery updated: 4080mV (90%) +[2026-02-20T18:21:27.767079] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2c 11 00 00 00 9d 23 00 00 +[2026-02-20T18:21:27.767172] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:27.767191] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:28.009405] LOG: [GPS SERVICE] Position stream fired: lat=47.36622, lon=-122.07525, accuracy=3.8m +[2026-02-20T18:21:28.009490] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger +[2026-02-20T18:21:28.009502] LOG: [RX BATCH] Distance check for repeater DB: 59.18m from first observation (threshold=25m) +[2026-02-20T18:21:28.009506] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush +[2026-02-20T18:21:28.009513] LOG: [RX BATCH] Distance check for repeater CC: 59.18m from first observation (threshold=25m) +[2026-02-20T18:21:28.009516] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:21:28.009519] LOG: [RX BATCH] Flushing repeater DB +[2026-02-20T18:21:28.009526] LOG: [RX BATCH] Cleared timeout timer for repeater DB +[2026-02-20T18:21:28.009532] LOG: [RX BATCH] Posting repeater DB: snr=-3.25, location=47.36569,-122.07524 +[2026-02-20T18:21:28.009536] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:28.009542] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=-3.25, location=47.36569,-122.07524 +[2026-02-20T18:21:28.009548] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best -3.25 <= pin -3.25 +[2026-02-20T18:21:28.009554] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=1 +[2026-02-20T18:21:28.009560] LOG: [APP] Added RX log entry: repeater=DB, snr=-3.25, pathLen=13 +[2026-02-20T18:21:28.009576] LOG: [RX BATCH] Repeater DB removed from buffer +[2026-02-20T18:21:28.009579] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:21:28.009584] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:21:28.009588] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36569,-122.07524 +[2026-02-20T18:21:28.009590] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:28.009596] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36569,-122.07524 +[2026-02-20T18:21:28.009600] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 +[2026-02-20T18:21:28.009605] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:21:28.009609] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=14 +[2026-02-20T18:21:28.009617] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:21:28.009620] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement +[2026-02-20T18:21:29.100761] LOG: [CONN] Frame received (73 bytes): 88 33 c1 15 01 cc 81 1d c9 ec 66 57 3e 6d d4 d4 56 e6 51 69 55 52 72 29 20 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 73 45 60 83 49 9f ac 54 b1 3f 61 af 4e e1 44 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:21:29.100885] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:29.100909] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:29.100962] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1D C9 EC 66 57 3E 6D D4 D4 56 E6 51 69 55 52 72 29 20 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 73 45 60 83 49 9F AC 54 B1 3F 61 AF 4E E1 44 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:21:29.100978] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:29.100987] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:21:29.101011] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-63, payload=67 bytes +[2026-02-20T18:21:29.101026] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:21:29.101036] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:21:29.101046] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-63 +[2026-02-20T18:21:29.101059] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:21:29.101067] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:21:29.101080] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:29.101088] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:29.101096] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:21:30.043070] LOG: [PING] Ping sent successfully +[2026-02-20T18:21:30.566818] LOG: [CONN] Frame received (74 bytes): 88 11 8f 15 02 cc db 81 1d c9 ec 66 57 3e 6d d4 d4 56 e6 51 69 55 52 72 29 20 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 73 45 60 83 49 9f ac 54 b1 3f 61 af 4e e1 44 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:21:30.566882] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:30.566894] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:30.566918] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 CC DB 81 1D C9 EC 66 57 3E 6D D4 D4 56 E6 51 69 55 52 72 29 20 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 73 45 60 83 49 9F AC 54 B1 3F 61 AF 4E E1 44 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:21:30.566922] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:30.566928] LOG: [RX PARSE] Path length offset: 1, Path length: 2 +[2026-02-20T18:21:30.566940] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0xcc, lastHop=0xdb, SNR=4.25, RSSI=-113, payload=67 bytes +[2026-02-20T18:21:30.566946] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 +[2026-02-20T18:21:30.566951] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:21:30.566955] LOG: [TX LOG] Processing rx_log entry: SNR=4.25, RSSI=-113 +[2026-02-20T18:21:30.566960] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:21:30.566964] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater db +[2026-02-20T18:21:30.566967] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) +[2026-02-20T18:21:30.566973] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 +[2026-02-20T18:21:30.566976] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel +[2026-02-20T18:21:30.566979] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... +[2026-02-20T18:21:30.566986] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:21:30.567019] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:21:30.567057] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... +[2026-02-20T18:21:30.567061] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.36569, -122.07524 [0.3w]" (47 chars) +[2026-02-20T18:21:30.567068] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.36569, -122.07524 [0.3w]" (40 chars) +[2026-02-20T18:21:30.567071] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! +[2026-02-20T18:21:30.567077] LOG: [PING] Repeater echo accepted: first_hop=db, SNR=null, full_path_length=2 (CARpeater stripped) +[2026-02-20T18:21:30.567085] LOG: [PING] Adding new repeater echo: path=db, SNR=null, RSSI=null +[2026-02-20T18:21:30.567090] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) +[2026-02-20T18:21:30.567096] LOG: [PING] onEchoReceived callback fired: db, SNR=null, RSSI=null, isNew=true +[2026-02-20T18:21:30.567103] LOG: [PING] Real-time: Added new repeater db (SNR: null) - total: 1 +[2026-02-20T18:21:30.567107] LOG: [PING] Calling onEchoReceived callback (callback=SET) +[2026-02-20T18:21:30.567113] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== +[2026-02-20T18:21:30.567118] LOG: [APP] Real-time echo: db (SNR: null, isNew: true) +[2026-02-20T18:21:30.567121] LOG: [APP] TxLogEntries count: 35 +[2026-02-20T18:21:30.567127] LOG: [APP] Updated TxLogEntry with 1 events (real-time) +[2026-02-20T18:21:30.567130] LOG: [APP] Calling notifyListeners() to update UI +[2026-02-20T18:21:30.567134] LOG: [APP] notifyListeners() completed +[2026-02-20T18:21:30.567139] LOG: [PING] onEchoReceived callback completed +[2026-02-20T18:21:30.567143] LOG: [TX LOG] onEchoReceived callback invoked successfully +[2026-02-20T18:21:30.567146] LOG: [TX LOG] ✅ Echo tracked successfully +[2026-02-20T18:21:30.567152] LOG: [UNIFIED RX] Packet was TX echo, done +[2026-02-20T18:21:31.984674] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) +[2026-02-20T18:21:31.984736] LOG: [TX LOG] Final: db -> SNR=null, seen=1x +[2026-02-20T18:21:32.462317] LOG: [CONN] Frame received (78 bytes): 88 23 9a 15 06 af d1 7a 74 32 db 11 34 1f 25 18 a3 2b 3a e9 f4 c0 d9 9b 67 37 a2 4b fd bb cc f6 88 74 66 88 f6 06 15 c6 13 4e 32 d5 9f 44 b3 8f d7 97 36 33 13 b4 82 75 c3 86 0b 6c d1 6f 16 99 8a 81 b8 1a 6c e6 5e 0e a5 12 55 de 50 49 +[2026-02-20T18:21:32.462428] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:32.462448] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:32.462593] LOG: [RX PARSE] RAW Packet (75 bytes): 15 06 AF D1 7A 74 32 DB 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 +[2026-02-20T18:21:32.462612] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:32.462663] LOG: [RX PARSE] Path length offset: 1, Path length: 6 +[2026-02-20T18:21:32.462693] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=6, firstHop=0xaf, lastHop=0xdb, SNR=8.75, RSSI=-102, payload=67 bytes +[2026-02-20T18:21:32.462703] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=6 +[2026-02-20T18:21:32.462715] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:32.462723] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:32.462781] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:32.462790] LOG: [RX FILTER] Raw packet (75 bytes): 15 06 AF D1 7A 74 32 DB 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 +[2026-02-20T18:21:32.462808] LOG: [RX FILTER] Header: 0x15 | PathLength: 6 | SNR: 8.75 +[2026-02-20T18:21:32.462818] LOG: [RX FILTER] ✓ RSSI OK (-102 < -30) +[2026-02-20T18:21:32.462830] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:32.462842] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:21:32.462850] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:21:32.462864] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:21:32.462874] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:21:32.462942] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:21:32.463083] LOG: [RX FILTER] Decrypted message (45 chars): "WXDev H3 : @[hankest] ack, Lynnwood, 3 hops" +[2026-02-20T18:21:32.463105] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) +[2026-02-20T18:21:32.463115] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:32.463139] LOG: [RX LOG] Packet heard via last hop: DB, SNR=8.75, path_length=6 +[2026-02-20T18:21:32.463148] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:32.463160] LOG: [RX BATCH] First observation for repeater DB: SNR=8.75 +[2026-02-20T18:21:32.463178] LOG: [RX BATCH] Started 30s timeout timer for repeater DB +[2026-02-20T18:21:32.463194] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:32.463213] LOG: [APP] Immediate RX observation: repeater=DB, snr=8.75, location=47.36622,-122.07525 +[2026-02-20T18:21:32.463228] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:21:32.463247] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36622,-122.07525 (batch tracking: 1 repeaters, rxCount: 37) +[2026-02-20T18:21:32.463264] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:32.463284] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=8.75, location=47.36622,-122.07525 +[2026-02-20T18:21:32.463628] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:21:32.463638] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:21:32.463650] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:21:32.603056] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:32.652865] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 9a 23 11 00 00 00 9e 23 00 00 +[2026-02-20T18:21:32.653018] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:32.653041] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:21:34.009848] LOG: [GPS SERVICE] Position stream fired: lat=47.36683, lon=-122.07525, accuracy=3.8m +[2026-02-20T18:21:34.009958] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:21:34.009970] LOG: [RX BATCH] Distance check for repeater DB: 67.66m from first observation (threshold=25m) +[2026-02-20T18:21:34.009977] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush +[2026-02-20T18:21:34.009982] LOG: [RX BATCH] Flushing repeater DB +[2026-02-20T18:21:34.009989] LOG: [RX BATCH] Cleared timeout timer for repeater DB +[2026-02-20T18:21:34.009998] LOG: [RX BATCH] Posting repeater DB: snr=8.75, location=47.36622,-122.07525 +[2026-02-20T18:21:34.010003] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:34.010007] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=8.75, location=47.36622,-122.07525 +[2026-02-20T18:21:34.010018] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 8.75 <= pin 8.75 +[2026-02-20T18:21:34.010023] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=0 +[2026-02-20T18:21:34.010030] LOG: [APP] Added RX log entry: repeater=DB, snr=8.75, pathLen=6 +[2026-02-20T18:21:34.010050] LOG: [RX BATCH] Repeater DB removed from buffer +[2026-02-20T18:21:34.010055] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:21:34.541614] LOG: [CONN] Frame received (79 bytes): 88 2e c7 15 07 af d1 7a 74 32 db cc 11 34 1f 25 18 a3 2b 3a e9 f4 c0 d9 9b 67 37 a2 4b fd bb cc f6 88 74 66 88 f6 06 15 c6 13 4e 32 d5 9f 44 b3 8f d7 97 36 33 13 b4 82 75 c3 86 0b 6c d1 6f 16 99 8a 81 b8 1a 6c e6 5e 0e a5 12 55 de 50 49 +[2026-02-20T18:21:34.541683] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:34.541695] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:34.541717] LOG: [RX PARSE] RAW Packet (76 bytes): 15 07 AF D1 7A 74 32 DB CC 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 +[2026-02-20T18:21:34.541723] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:34.541725] LOG: [RX PARSE] Path length offset: 1, Path length: 7 +[2026-02-20T18:21:34.541738] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xaf, lastHop=0xcc, SNR=11.5, RSSI=-57, payload=67 bytes +[2026-02-20T18:21:34.541743] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 +[2026-02-20T18:21:34.541745] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:34.541749] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:34.541772] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:34.541775] LOG: [RX FILTER] Raw packet (76 bytes): 15 07 AF D1 7A 74 32 DB CC 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 +[2026-02-20T18:21:34.541782] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.5 +[2026-02-20T18:21:34.541786] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:21:34.541789] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:34.541794] LOG: [RX FILTER] Channel hash: 0x11 +[2026-02-20T18:21:34.541799] LOG: [RX FILTER] ✓ Channel matched: Public +[2026-02-20T18:21:34.541802] LOG: [RX FILTER] Encrypted message: 64 bytes +[2026-02-20T18:21:34.541807] LOG: [CRYPTO] Decrypting message (64 bytes) +[2026-02-20T18:21:34.541835] LOG: [CRYPTO] Decrypted successfully (64 bytes) +[2026-02-20T18:21:34.541901] LOG: [RX FILTER] Decrypted message (45 chars): "WXDev H3 : @[hankest] ack, Lynnwood, 3 hops" +[2026-02-20T18:21:34.541908] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) +[2026-02-20T18:21:34.541910] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:34.541921] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=7 +[2026-02-20T18:21:34.541925] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:34.541931] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 +[2026-02-20T18:21:34.541941] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:21:34.541948] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:34.541953] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.36683,-122.07525 +[2026-02-20T18:21:34.541961] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:21:34.541968] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36683,-122.07525 (batch tracking: 1 repeaters, rxCount: 38) +[2026-02-20T18:21:34.541977] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:21:34.541983] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.36683,-122.07525 +[2026-02-20T18:21:35.043730] LOG: [PING] RX listening window ended +[2026-02-20T18:21:35.043855] LOG: [PING] TxTracker collected 1 repeater echoes +[2026-02-20T18:21:35.043869] LOG: [PING] Heard repeater: db, SNR=null +[2026-02-20T18:21:35.044038] LOG: [GRAPH] Recorded txSuccess event at -119dBm with 1 repeater(s) +[2026-02-20T18:21:35.044082] LOG: [PING] Queued TX entry with heard_repeats: db(null) +[2026-02-20T18:21:35.044091] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:21:35.044098] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:21:35.044114] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:21:35.044122] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:21:35.044514] LOG: [API QUEUE] TX enqueued: db(null) (queue size: 1) +[2026-02-20T18:21:37.573642] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:21:37.573728] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true +[2026-02-20T18:21:37.573734] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true +[2026-02-20T18:21:37.573737] LOG: [API QUEUE] Uploading 2 items... +[2026-02-20T18:21:37.579132] LOG: [API QUEUE] Flushed 3 RX items from 2 repeaters to queue +[2026-02-20T18:21:37.602697] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:37.783573] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2e 11 00 00 00 9e 23 00 00 +[2026-02-20T18:21:37.783706] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:37.783726] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:38.118960] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:21:38.119055] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:21:38.119074] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771640797} +[2026-02-20T18:21:38.119093] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:21:38.119117] LOG: [API] Upload batch SUCCESS: 2 items +[2026-02-20T18:21:38.119944] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items +[2026-02-20T18:21:38.119961] LOG: [APP] Upload success: +2 items (total: 70) +[2026-02-20T18:21:39.077107] LOG: [GPS SERVICE] Position stream fired: lat=47.36708, lon=-122.07502, accuracy=3.8m +[2026-02-20T18:21:39.077201] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:21:39.077211] LOG: [RX BATCH] Distance check for repeater CC: 32.47m from first observation (threshold=25m) +[2026-02-20T18:21:39.077216] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:21:39.077220] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:21:39.077226] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:21:39.077234] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.36683,-122.07525 +[2026-02-20T18:21:39.077238] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:39.077242] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.36683,-122.07525 +[2026-02-20T18:21:39.077250] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 +[2026-02-20T18:21:39.077257] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:21:39.077263] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=7 +[2026-02-20T18:21:39.077280] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:21:39.077285] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:21:40.045636] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:21:40.045914] LOG: [API QUEUE] Item 1/3: type=RX, external_antenna=true +[2026-02-20T18:21:40.045927] LOG: [API QUEUE] Item 2/3: type=RX, external_antenna=true +[2026-02-20T18:21:40.045936] LOG: [API QUEUE] Item 3/3: type=RX, external_antenna=true +[2026-02-20T18:21:40.045948] LOG: [API QUEUE] Uploading 3 items... +[2026-02-20T18:21:40.046999] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue +[2026-02-20T18:21:40.436141] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:21:40.436247] LOG: [API] Request: {"data":"3 items","items":"RX:external_antenna=true, RX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:21:40.436266] LOG: [API] Response (200) in 0.39s: {"success":true,"expires_at":1771640800} +[2026-02-20T18:21:40.436283] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:21:40.436309] LOG: [API] Upload batch SUCCESS: 3 items +[2026-02-20T18:21:40.441348] LOG: [API QUEUE] Upload SUCCESS: deleted 3 items +[2026-02-20T18:21:40.441386] LOG: [APP] Upload success: +3 items (total: 73) +[2026-02-20T18:21:42.231873] LOG: [CONN] Frame received (91 bytes): 88 0f 8f 15 03 e8 7e 02 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 +[2026-02-20T18:21:42.231933] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:42.231974] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:42.232055] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:42.232079] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:42.232091] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:21:42.232121] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x02, SNR=3.75, RSSI=-113, payload=83 bytes +[2026-02-20T18:21:42.232141] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:21:42.232151] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:42.232166] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:42.232253] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:42.232264] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:42.232289] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 3.75 +[2026-02-20T18:21:42.232303] LOG: [RX FILTER] ✓ RSSI OK (-113 < -30) +[2026-02-20T18:21:42.232319] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:42.232331] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:42.232343] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:42.232360] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:42.232372] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:42.232473] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:42.232663] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." +[2026-02-20T18:21:42.232694] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:42.232706] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:42.232828] LOG: [RX LOG] Packet heard via last hop: 02, SNR=3.75, path_length=3 +[2026-02-20T18:21:42.232841] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:42.232862] LOG: [RX BATCH] First observation for repeater 02: SNR=3.75 +[2026-02-20T18:21:42.232878] LOG: [RX BATCH] Started 30s timeout timer for repeater 02 +[2026-02-20T18:21:42.232902] LOG: [RX BATCH] Distance check for repeater 02: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:42.232923] LOG: [APP] Immediate RX observation: repeater=02, snr=3.75, location=47.36708,-122.07502 +[2026-02-20T18:21:42.232946] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:21:42.232966] LOG: [APP] Created IMMEDIATE RX pin for repeater: 02 at 47.36708,-122.07502 (batch tracking: 1 repeaters, rxCount: 39) +[2026-02-20T18:21:42.232986] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:42.233010] LOG: [RX LOG] ✅ Observation kept in batch: repeater=02, snr=3.75, location=47.36708,-122.07502 +[2026-02-20T18:21:42.233491] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:21:42.233511] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:21:42.233523] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:21:42.506980] LOG: [CONN] Frame received (91 bytes): 88 0e 8e 15 03 e8 7e 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 +[2026-02-20T18:21:42.507100] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:42.507128] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:42.507207] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:42.507229] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:42.507241] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:21:42.507271] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x6c, SNR=3.5, RSSI=-114, payload=83 bytes +[2026-02-20T18:21:42.507282] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:21:42.507295] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:42.507304] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:42.507363] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:42.507377] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:42.507391] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 3.5 +[2026-02-20T18:21:42.507409] LOG: [RX FILTER] ✓ RSSI OK (-114 < -30) +[2026-02-20T18:21:42.507418] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:42.507425] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:42.507440] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:42.507450] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:42.507457] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:42.507558] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:42.507612] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." +[2026-02-20T18:21:42.507629] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:42.507635] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:42.507661] LOG: [RX LOG] Packet heard via last hop: 6C, SNR=3.5, path_length=3 +[2026-02-20T18:21:42.507673] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:42.507687] LOG: [RX BATCH] First observation for repeater 6C: SNR=3.5 +[2026-02-20T18:21:42.507700] LOG: [RX BATCH] Started 30s timeout timer for repeater 6C +[2026-02-20T18:21:42.507720] LOG: [RX BATCH] Distance check for repeater 6C: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:42.507736] LOG: [APP] Immediate RX observation: repeater=6C, snr=3.5, location=47.36708,-122.07502 +[2026-02-20T18:21:42.507764] LOG: [APP] Current batch tracking: 1 repeaters: {02} +[2026-02-20T18:21:42.507781] LOG: [APP] Created IMMEDIATE RX pin for repeater: 6C at 47.36708,-122.07502 (batch tracking: 2 repeaters, rxCount: 40) +[2026-02-20T18:21:42.507801] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:42.507816] LOG: [RX LOG] ✅ Observation kept in batch: repeater=6C, snr=3.5, location=47.36708,-122.07502 +[2026-02-20T18:21:42.604342] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:42.706594] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 8e 0e 11 00 00 00 9f 23 00 00 +[2026-02-20T18:21:42.706723] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:42.706748] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:43.558047] LOG: [CONN] Frame received (91 bytes): 88 29 9d 15 03 e8 7e db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 +[2026-02-20T18:21:43.558107] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:43.558117] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:43.558142] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:43.558148] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:43.558154] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:21:43.558163] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xdb, SNR=10.25, RSSI=-99, payload=83 bytes +[2026-02-20T18:21:43.558168] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:21:43.558172] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:43.558175] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:43.558195] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:43.558201] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:43.558207] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 10.25 +[2026-02-20T18:21:43.558213] LOG: [RX FILTER] ✓ RSSI OK (-99 < -30) +[2026-02-20T18:21:43.558216] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:43.558220] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:43.558225] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:43.558228] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:43.558233] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:43.558262] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:43.558328] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." +[2026-02-20T18:21:43.558334] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:43.558338] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:43.558348] LOG: [RX LOG] Packet heard via last hop: DB, SNR=10.25, path_length=3 +[2026-02-20T18:21:43.558353] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:43.558358] LOG: [RX BATCH] First observation for repeater DB: SNR=10.25 +[2026-02-20T18:21:43.558366] LOG: [RX BATCH] Started 30s timeout timer for repeater DB +[2026-02-20T18:21:43.558374] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:43.558380] LOG: [APP] Immediate RX observation: repeater=DB, snr=10.25, location=47.36708,-122.07502 +[2026-02-20T18:21:43.558387] LOG: [APP] Current batch tracking: 2 repeaters: {02, 6C} +[2026-02-20T18:21:43.558393] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36708,-122.07502 (batch tracking: 3 repeaters, rxCount: 41) +[2026-02-20T18:21:43.558401] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:43.558407] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=10.25, location=47.36708,-122.07502 +[2026-02-20T18:21:43.744845] LOG: [GPS SERVICE] Position stream fired: lat=47.36709, lon=-122.07439, accuracy=3.8m +[2026-02-20T18:21:43.744944] LOG: [RX BATCH] Checking 3 active batch(es) for distance trigger +[2026-02-20T18:21:43.744959] LOG: [RX BATCH] Distance check for repeater 02: 47.61m from first observation (threshold=25m) +[2026-02-20T18:21:43.744963] LOG: [RX BATCH] Distance threshold met for repeater 02, marking for flush +[2026-02-20T18:21:43.744967] LOG: [RX BATCH] Distance check for repeater 6C: 47.61m from first observation (threshold=25m) +[2026-02-20T18:21:43.744973] LOG: [RX BATCH] Distance threshold met for repeater 6C, marking for flush +[2026-02-20T18:21:43.744977] LOG: [RX BATCH] Distance check for repeater DB: 47.61m from first observation (threshold=25m) +[2026-02-20T18:21:43.744981] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush +[2026-02-20T18:21:43.744986] LOG: [RX BATCH] Flushing repeater 02 +[2026-02-20T18:21:43.744991] LOG: [RX BATCH] Cleared timeout timer for repeater 02 +[2026-02-20T18:21:43.744999] LOG: [RX BATCH] Posting repeater 02: snr=3.75, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745002] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:43.745007] LOG: [APP] Finalized RX entry (best SNR): repeater=02, snr=3.75, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745018] LOG: [APP] RX pin SNR unchanged for repeater=02: batch best 3.75 <= pin 3.75 +[2026-02-20T18:21:43.745023] LOG: [APP] Cleared batch tracking for 02: wasPresent=true, remaining=2 +[2026-02-20T18:21:43.745030] LOG: [APP] Added RX log entry: repeater=02, snr=3.75, pathLen=3 +[2026-02-20T18:21:43.745051] LOG: [RX BATCH] Repeater 02 removed from buffer +[2026-02-20T18:21:43.745056] LOG: [RX BATCH] Flushing repeater 6C +[2026-02-20T18:21:43.745060] LOG: [RX BATCH] Cleared timeout timer for repeater 6C +[2026-02-20T18:21:43.745068] LOG: [RX BATCH] Posting repeater 6C: snr=3.5, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745071] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:43.745074] LOG: [APP] Finalized RX entry (best SNR): repeater=6C, snr=3.5, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745082] LOG: [APP] RX pin SNR unchanged for repeater=6C: batch best 3.50 <= pin 3.50 +[2026-02-20T18:21:43.745086] LOG: [APP] Cleared batch tracking for 6C: wasPresent=true, remaining=1 +[2026-02-20T18:21:43.745091] LOG: [APP] Added RX log entry: repeater=6C, snr=3.5, pathLen=3 +[2026-02-20T18:21:43.745097] LOG: [RX BATCH] Repeater 6C removed from buffer +[2026-02-20T18:21:43.745104] LOG: [RX BATCH] Flushing repeater DB +[2026-02-20T18:21:43.745107] LOG: [RX BATCH] Cleared timeout timer for repeater DB +[2026-02-20T18:21:43.745111] LOG: [RX BATCH] Posting repeater DB: snr=10.25, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745114] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:43.745117] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=10.25, location=47.36708,-122.07502 +[2026-02-20T18:21:43.745124] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 10.25 <= pin 10.25 +[2026-02-20T18:21:43.745126] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=0 +[2026-02-20T18:21:43.745129] LOG: [APP] Added RX log entry: repeater=DB, snr=10.25, pathLen=3 +[2026-02-20T18:21:43.745137] LOG: [RX BATCH] Repeater DB removed from buffer +[2026-02-20T18:21:43.745155] LOG: [RX BATCH] Flushed 3 repeater(s) due to GPS movement +[2026-02-20T18:21:44.208887] LOG: [CONN] Frame received (92 bytes): 88 30 cc 15 04 e8 7e 02 cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 +[2026-02-20T18:21:44.209068] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:44.209090] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:44.209145] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 E8 7E 02 CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:44.209157] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:44.209167] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:21:44.209189] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-52, payload=83 bytes +[2026-02-20T18:21:44.209206] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:21:44.209212] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:44.209218] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:44.209267] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:44.209275] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 E8 7E 02 CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 +[2026-02-20T18:21:44.209289] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 +[2026-02-20T18:21:44.209299] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) +[2026-02-20T18:21:44.209305] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:44.209315] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:44.209324] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:44.209331] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:21:44.209341] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:21:44.209407] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:21:44.209528] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." +[2026-02-20T18:21:44.209543] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:21:44.209552] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:21:44.209573] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 +[2026-02-20T18:21:44.209579] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:21:44.209589] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 +[2026-02-20T18:21:44.209604] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:21:44.209616] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:21:44.209632] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.36709,-122.07439 +[2026-02-20T18:21:44.209645] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:21:44.209658] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36709,-122.07439 (batch tracking: 1 repeaters, rxCount: 42) +[2026-02-20T18:21:44.209676] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) +[2026-02-20T18:21:44.209689] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.36709,-122.07439 +[2026-02-20T18:21:45.441642] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:21:47.603389] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:47.716056] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 30 11 00 00 00 9f 23 00 00 +[2026-02-20T18:21:47.716185] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:47.716205] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:49.073771] LOG: [GPS SERVICE] Position stream fired: lat=47.36709, lon=-122.07367, accuracy=3.8m +[2026-02-20T18:21:49.073878] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger +[2026-02-20T18:21:49.073895] LOG: [RX BATCH] Distance check for repeater CC: 54.02m from first observation (threshold=25m) +[2026-02-20T18:21:49.073899] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush +[2026-02-20T18:21:49.073903] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:21:49.073913] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:21:49.073922] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.36709,-122.07439 +[2026-02-20T18:21:49.073927] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:21:49.073931] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.36709,-122.07439 +[2026-02-20T18:21:49.073939] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 +[2026-02-20T18:21:49.073947] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:21:49.073952] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 +[2026-02-20T18:21:49.074023] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:21:49.074030] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement +[2026-02-20T18:21:49.564967] LOG: [CONN] Frame received (95 bytes): 88 27 97 15 0a e8 7e 75 20 20 20 20 53 7e db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 +[2026-02-20T18:21:49.565028] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:49.565044] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:49.565076] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:49.565086] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:49.565091] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:21:49.565107] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xe8, lastHop=0xdb, SNR=9.75, RSSI=-105, payload=80 bytes +[2026-02-20T18:21:49.565114] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:21:49.565118] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:49.565124] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:49.565160] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:49.565164] LOG: [RX FILTER] Raw packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:49.565173] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 9.75 +[2026-02-20T18:21:49.565178] LOG: [RX FILTER] ✓ RSSI OK (-105 < -30) +[2026-02-20T18:21:49.565185] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:49.565190] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:49.565194] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:49.565201] LOG: [RX FILTER] Encrypted message: 77 bytes +[2026-02-20T18:21:49.565207] LOG: [CRYPTO] Decrypting message (77 bytes) +[2026-02-20T18:21:49.565286] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:49.565304] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:49.565405] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:49.565470] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:49.565475] LOG: [RX LOG] Dropped packet hex: 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:50.421584] LOG: [CONN] Frame received (95 bytes): 88 31 c4 15 0a e8 7e 75 20 20 20 20 53 7e cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 +[2026-02-20T18:21:50.421760] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:50.421800] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:50.421888] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:50.421913] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:50.421925] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:21:50.421957] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xe8, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=80 bytes +[2026-02-20T18:21:50.421978] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 +[2026-02-20T18:21:50.421989] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:50.422004] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:50.422097] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:50.422110] LOG: [RX FILTER] Raw packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:50.422135] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 +[2026-02-20T18:21:50.422150] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) +[2026-02-20T18:21:50.422165] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:50.422178] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:50.422190] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:50.422207] LOG: [RX FILTER] Encrypted message: 77 bytes +[2026-02-20T18:21:50.422219] LOG: [CRYPTO] Decrypting message (77 bytes) +[2026-02-20T18:21:50.422432] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:50.422490] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:50.422755] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:50.422832] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:50.422840] LOG: [RX LOG] Dropped packet hex: 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 +[2026-02-20T18:21:52.573666] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:21:52.573789] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true +[2026-02-20T18:21:52.573798] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:21:52.575343] LOG: [API QUEUE] Flushed 4 RX items from 4 repeaters to queue +[2026-02-20T18:21:52.602851] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:52.726718] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 11 00 00 00 a0 23 00 00 +[2026-02-20T18:21:52.726825] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:52.726840] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:53.075015] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:21:53.075069] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} +[2026-02-20T18:21:53.075083] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771640812} +[2026-02-20T18:21:53.075095] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:21:53.075110] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:21:53.075353] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:21:53.075368] LOG: [APP] Upload success: +1 items (total: 74) +[2026-02-20T18:21:54.073835] LOG: [GPS SERVICE] Position stream fired: lat=47.36733, lon=-122.07340, accuracy=3.8m +[2026-02-20T18:21:54.073936] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:21:54.073965] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:21:56.131405] LOG: [CONN] Frame received (95 bytes): 88 24 99 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 c7 db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e +[2026-02-20T18:21:56.131590] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:56.131624] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:56.131725] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.131745] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:56.131763] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:21:56.131805] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xdb, SNR=9.0, RSSI=-103, payload=76 bytes +[2026-02-20T18:21:56.131824] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:21:56.131837] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:56.131846] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:56.131924] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:56.131943] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.132041] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 9.0 +[2026-02-20T18:21:56.132057] LOG: [RX FILTER] ✓ RSSI OK (-103 < -30) +[2026-02-20T18:21:56.132069] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:56.132087] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:56.132101] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:56.132115] LOG: [RX FILTER] Encrypted message: 73 bytes +[2026-02-20T18:21:56.132134] LOG: [CRYPTO] Decrypting message (73 bytes) +[2026-02-20T18:21:56.132347] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.132402] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.132649] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:56.132784] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:56.132796] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.508603] LOG: [CONN] Frame received (95 bytes): 88 01 8b 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 7e 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e +[2026-02-20T18:21:56.508664] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:56.508705] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:56.508786] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.508809] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:56.508824] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:21:56.508855] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x6c, SNR=0.25, RSSI=-117, payload=76 bytes +[2026-02-20T18:21:56.508868] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:21:56.508883] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:56.508893] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:56.508981] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:56.509033] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.509058] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 0.25 +[2026-02-20T18:21:56.509074] LOG: [RX FILTER] ✓ RSSI OK (-117 < -30) +[2026-02-20T18:21:56.509086] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:56.509100] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:56.509113] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:56.509125] LOG: [RX FILTER] Encrypted message: 73 bytes +[2026-02-20T18:21:56.509140] LOG: [CRYPTO] Decrypting message (73 bytes) +[2026-02-20T18:21:56.509325] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.509484] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.509716] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:56.509844] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:56.509856] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.930380] LOG: [CONN] Frame received (95 bytes): 88 2f c5 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 7e cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e +[2026-02-20T18:21:56.930585] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:21:56.930624] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:21:56.930741] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.930764] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:21:56.930776] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:21:56.930811] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xcc, SNR=11.75, RSSI=-59, payload=76 bytes +[2026-02-20T18:21:56.930826] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:21:56.930836] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:21:56.930860] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:21:56.930941] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:21:56.930954] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:56.931207] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 11.75 +[2026-02-20T18:21:56.931229] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) +[2026-02-20T18:21:56.931242] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:21:56.931252] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:21:56.931263] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:21:56.931282] LOG: [RX FILTER] Encrypted message: 73 bytes +[2026-02-20T18:21:56.931292] LOG: [CRYPTO] Decrypting message (73 bytes) +[2026-02-20T18:21:56.931480] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.931532] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:21:56.931748] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:21:56.931870] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:21:56.931896] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E +[2026-02-20T18:21:57.602850] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:21:57.603059] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:21:57.737088] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:21:57.737230] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:21:57.737253] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:21:57.737269] LOG: [CONN] Battery updated: 4076mV (90%) +[2026-02-20T18:21:57.795534] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 11 00 00 00 a1 23 00 00 +[2026-02-20T18:21:57.795659] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:21:57.795680] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:21:58.076202] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:21:58.759254] LOG: [GPS SERVICE] Position stream fired: lat=47.36765, lon=-122.07335, accuracy=3.8m +[2026-02-20T18:22:00.650280] LOG: [CONN] Frame received (102 bytes): 88 2f a9 15 16 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 +[2026-02-20T18:22:00.650428] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:00.650457] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:00.650613] LOG: [RX PARSE] RAW Packet (99 bytes): 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:00.650655] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:00.650667] LOG: [RX PARSE] Path length offset: 1, Path length: 22 +[2026-02-20T18:22:00.650688] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-87, payload=75 bytes +[2026-02-20T18:22:00.650707] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 +[2026-02-20T18:22:00.650718] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:00.650734] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:00.650819] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:00.650835] LOG: [RX FILTER] Raw packet (99 bytes): 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:00.650857] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 11.75 +[2026-02-20T18:22:00.650875] LOG: [RX FILTER] ✓ RSSI OK (-87 < -30) +[2026-02-20T18:22:00.650886] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:00.650897] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:00.650912] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:00.650924] LOG: [RX FILTER] Encrypted message: 72 bytes +[2026-02-20T18:22:00.650935] LOG: [CRYPTO] Decrypting message (72 bytes) +[2026-02-20T18:22:00.651122] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:00.651174] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:00.651415] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:00.651545] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:00.651557] LOG: [RX LOG] Dropped packet hex: 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.201473] LOG: [CONN] Frame received (103 bytes): 88 2c 9d 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 +[2026-02-20T18:22:01.201645] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:01.201678] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:01.201777] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.201801] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:01.201816] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T18:22:01.201853] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0x6c, SNR=11.0, RSSI=-99, payload=75 bytes +[2026-02-20T18:22:01.201869] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 +[2026-02-20T18:22:01.201879] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:01.201895] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:01.201986] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:01.202011] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.202035] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.0 +[2026-02-20T18:22:01.202056] LOG: [RX FILTER] ✓ RSSI OK (-99 < -30) +[2026-02-20T18:22:01.202067] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:01.202079] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:01.202101] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:01.202114] LOG: [RX FILTER] Encrypted message: 72 bytes +[2026-02-20T18:22:01.202129] LOG: [CRYPTO] Decrypting message (72 bytes) +[2026-02-20T18:22:01.202335] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:01.202389] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:01.202772] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:01.202919] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:01.202937] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.731275] LOG: [CONN] Frame received (103 bytes): 88 29 9e 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 02 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 +[2026-02-20T18:22:01.731336] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:01.731376] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:01.731466] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.731490] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:01.731504] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T18:22:01.731532] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0x02, SNR=10.25, RSSI=-98, payload=75 bytes +[2026-02-20T18:22:01.731552] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 +[2026-02-20T18:22:01.731562] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:01.731589] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:01.731686] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:01.731698] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:01.731723] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 10.25 +[2026-02-20T18:22:01.731742] LOG: [RX FILTER] ✓ RSSI OK (-98 < -30) +[2026-02-20T18:22:01.731754] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:01.731764] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:01.731780] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:01.731793] LOG: [RX FILTER] Encrypted message: 72 bytes +[2026-02-20T18:22:01.731803] LOG: [CRYPTO] Decrypting message (72 bytes) +[2026-02-20T18:22:01.732005] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:01.732163] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:01.732374] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:01.732517] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:01.732535] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:02.370240] LOG: [CONN] Frame received (103 bytes): 88 2f cd 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 +[2026-02-20T18:22:02.370342] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:02.370364] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:02.370407] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:02.370419] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:02.370424] LOG: [RX PARSE] Path length offset: 1, Path length: 23 +[2026-02-20T18:22:02.370443] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0xcc, SNR=11.75, RSSI=-51, payload=75 bytes +[2026-02-20T18:22:02.370450] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 +[2026-02-20T18:22:02.370455] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:02.370462] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:02.370500] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:02.370509] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:02.370612] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.75 +[2026-02-20T18:22:02.370620] LOG: [RX FILTER] ✓ RSSI OK (-51 < -30) +[2026-02-20T18:22:02.370625] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:02.370648] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:02.370666] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:02.370743] LOG: [RX FILTER] Encrypted message: 72 bytes +[2026-02-20T18:22:02.370752] LOG: [CRYPTO] Decrypting message (72 bytes) +[2026-02-20T18:22:02.370890] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:02.370944] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:02.371054] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:02.371114] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:02.371122] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 +[2026-02-20T18:22:02.604310] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:02.714939] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff cd 2f 11 00 00 00 a2 23 00 00 +[2026-02-20T18:22:02.715101] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:02.715122] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:22:03.754989] LOG: [GPS SERVICE] Position stream fired: lat=47.36804, lon=-122.07333, accuracy=3.9m +[2026-02-20T18:22:05.009841] LOG: [CONN] Frame received (33 bytes): 88 19 a3 01 08 f2 f5 56 ab 5a 7a 7e 02 f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc +[2026-02-20T18:22:05.009968] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:05.010046] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:05.010083] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.010094] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:22:05.010107] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:05.010130] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0x02, SNR=6.25, RSSI=-93, payload=20 bytes +[2026-02-20T18:22:05.010145] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 +[2026-02-20T18:22:05.010153] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:05.010161] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:05.010192] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:05.010205] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.010217] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 6.25 +[2026-02-20T18:22:05.010232] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) +[2026-02-20T18:22:05.010243] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:22:05.010279] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:05.010288] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.045005] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:22:05.045130] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:22:05.045148] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:22:05.045190] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:22:05.045237] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36804, -122.07333 [0.3w]" +[2026-02-20T18:22:05.045250] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:22:05.045265] LOG: [TX LOG] Payload: "@[MapperBot] 47.36804, -122.07333 [0.3w]" +[2026-02-20T18:22:05.045279] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:22:05.045292] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:22:05.045310] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:22:05.045321] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:22:05.045356] LOG: [CONN] Sending ping: @[MapperBot] 47.36804, -122.07333 [0.3w] +[2026-02-20T18:22:05.301375] LOG: [CONN] Frame received (33 bytes): 88 2f ce 01 08 f2 f5 56 ab 5a 7a 7e cc f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc +[2026-02-20T18:22:05.301514] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:05.301669] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:05.301737] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.301752] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:22:05.301769] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:05.301790] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0xcc, SNR=11.75, RSSI=-50, payload=20 bytes +[2026-02-20T18:22:05.301808] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 +[2026-02-20T18:22:05.301818] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:22:05.301830] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-50 +[2026-02-20T18:22:05.301847] LOG: [TX LOG] Ignoring: header validation failed (header=0x01) +[2026-02-20T18:22:05.301860] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:05.301874] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:05.301913] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:05.301925] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.301943] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 11.75 +[2026-02-20T18:22:05.301958] LOG: [RX FILTER] ✓ RSSI OK (-50 < -30) +[2026-02-20T18:22:05.301970] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:22:05.302014] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:05.302027] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.322405] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:22:05.322505] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:22:05.322598] LOG: [CONN] Received OK response +[2026-02-20T18:22:05.867546] LOG: [CONN] Frame received (33 bytes): 88 2f ab 01 08 f2 f5 56 ab 5a 7a 7e db f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc +[2026-02-20T18:22:05.867690] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:05.867732] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:05.867797] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.867811] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:22:05.867822] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:05.867850] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0xdb, SNR=11.75, RSSI=-85, payload=20 bytes +[2026-02-20T18:22:05.867863] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 +[2026-02-20T18:22:05.867878] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:22:05.867891] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-85 +[2026-02-20T18:22:05.867902] LOG: [TX LOG] Ignoring: header validation failed (header=0x01) +[2026-02-20T18:22:05.867919] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:05.867929] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:05.867966] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:05.867984] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:05.867998] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 11.75 +[2026-02-20T18:22:05.868016] LOG: [RX FILTER] ✓ RSSI OK (-85 < -30) +[2026-02-20T18:22:05.868031] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:22:05.868072] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:05.868089] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC +[2026-02-20T18:22:07.573739] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:22:07.573865] LOG: [API QUEUE] Item 1/3: type=RX, external_antenna=true +[2026-02-20T18:22:07.573881] LOG: [API QUEUE] Item 2/3: type=RX, external_antenna=true +[2026-02-20T18:22:07.573898] LOG: [API QUEUE] Item 3/3: type=RX, external_antenna=true +[2026-02-20T18:22:07.573908] LOG: [API QUEUE] Uploading 3 items... +[2026-02-20T18:22:07.605056] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:07.724065] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ab 2f 11 00 00 00 a3 23 00 00 +[2026-02-20T18:22:07.724208] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:07.724228] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:22:08.008587] LOG: [GPS SERVICE] Position stream fired: lat=47.36830, lon=-122.07310, accuracy=3.8m +[2026-02-20T18:22:08.034751] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:22:08.034791] LOG: [API] Request: {"data":"3 items","items":"RX:external_antenna=true, RX:external_antenna=true, RX:external_antenna=true"} +[2026-02-20T18:22:08.034799] LOG: [API] Response (200) in 0.46s: {"success":true,"expires_at":1771640827} +[2026-02-20T18:22:08.034804] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) +[2026-02-20T18:22:08.034813] LOG: [API] Upload batch SUCCESS: 3 items +[2026-02-20T18:22:08.037386] LOG: [API QUEUE] Upload SUCCESS: deleted 3 items +[2026-02-20T18:22:08.037404] LOG: [APP] Upload success: +3 items (total: 77) +[2026-02-20T18:22:08.324294] LOG: [PING] Ping sent successfully +[2026-02-20T18:22:10.045942] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:22:10.070459] LOG: [CONN] Frame received (51 bytes): 88 30 cb 21 0a 07 1b ab 50 5a 15 e0 7a 7e cc 2b f4 ef 98 16 4c 7a af fc e6 fd ea 00 94 51 26 ec 3b d6 a0 74 78 31 21 ff 0b 87 d6 43 9b 23 5b 62 64 7f ca +[2026-02-20T18:22:10.070643] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:10.070668] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:10.070717] LOG: [RX PARSE] RAW Packet (48 bytes): 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:10.070732] LOG: [RX PARSE] Header: 0x21, Route type: 1 +[2026-02-20T18:22:10.070741] LOG: [RX PARSE] Path length offset: 1, Path length: 10 +[2026-02-20T18:22:10.070769] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=10, firstHop=0x07, lastHop=0xcc, SNR=12.0, RSSI=-53, payload=36 bytes +[2026-02-20T18:22:10.070781] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=10 +[2026-02-20T18:22:10.070789] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:10.070802] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:10.070840] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:10.070849] LOG: [RX FILTER] Raw packet (48 bytes): 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:10.070866] LOG: [RX FILTER] Header: 0x21 | PathLength: 10 | SNR: 12.0 +[2026-02-20T18:22:10.070877] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) +[2026-02-20T18:22:10.070890] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x21) +[2026-02-20T18:22:10.070933] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:10.070946] LOG: [RX LOG] Dropped packet hex: 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:11.030068] LOG: [CONN] Frame received (52 bytes): 88 2f ae 21 0b 07 1b ab 50 5a 15 e0 7a 7e 6c db 2b f4 ef 98 16 4c 7a af fc e6 fd ea 00 94 51 26 ec 3b d6 a0 74 78 31 21 ff 0b 87 d6 43 9b 23 5b 62 64 7f ca +[2026-02-20T18:22:11.030160] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:11.030177] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:11.030204] LOG: [RX PARSE] RAW Packet (49 bytes): 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:11.030210] LOG: [RX PARSE] Header: 0x21, Route type: 1 +[2026-02-20T18:22:11.030219] LOG: [RX PARSE] Path length offset: 1, Path length: 11 +[2026-02-20T18:22:11.030236] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=11, firstHop=0x07, lastHop=0xdb, SNR=11.75, RSSI=-82, payload=36 bytes +[2026-02-20T18:22:11.030248] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=11 +[2026-02-20T18:22:11.030252] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:11.030256] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:11.030281] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:11.030286] LOG: [RX FILTER] Raw packet (49 bytes): 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:11.030296] LOG: [RX FILTER] Header: 0x21 | PathLength: 11 | SNR: 11.75 +[2026-02-20T18:22:11.030303] LOG: [RX FILTER] ✓ RSSI OK (-82 < -30) +[2026-02-20T18:22:11.030308] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x21) +[2026-02-20T18:22:11.030335] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:11.030343] LOG: [RX LOG] Dropped packet hex: 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA +[2026-02-20T18:22:12.603050] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:12.762865] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ae 2f 11 00 00 00 a3 23 00 00 +[2026-02-20T18:22:12.763016] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:12.763044] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:22:13.039954] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:22:13.326165] LOG: [PING] RX listening window ended +[2026-02-20T18:22:13.326211] LOG: [PING] No repeater echoes detected during listening window +[2026-02-20T18:22:13.326229] LOG: [GRAPH] Recorded txFail event at -118dBm +[2026-02-20T18:22:13.326266] LOG: [PING] Queued TX entry with heard_repeats: None +[2026-02-20T18:22:13.326272] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion +[2026-02-20T18:22:13.326280] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms +[2026-02-20T18:22:13.326293] LOG: [ACTIVE MODE] New timer scheduled +[2026-02-20T18:22:13.326299] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:22:13.328337] LOG: [API QUEUE] TX enqueued: None (queue size: 1) +[2026-02-20T18:22:15.014084] LOG: [GPS SERVICE] Position stream fired: lat=47.36845, lon=-122.07288, accuracy=3.8m +[2026-02-20T18:22:15.047695] LOG: [CONN] Frame received (39 bytes): 88 2d b4 01 12 f2 f5 56 ab 5a 7a 7e 75 20 20 20 53 fc 7a 86 e8 7e 6c f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c +[2026-02-20T18:22:15.047753] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:15.047765] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:15.047776] LOG: [RX PARSE] RAW Packet (36 bytes): 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:15.047780] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:22:15.047783] LOG: [RX PARSE] Path length offset: 1, Path length: 18 +[2026-02-20T18:22:15.047794] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=18, firstHop=0xf2, lastHop=0x6c, SNR=11.25, RSSI=-76, payload=16 bytes +[2026-02-20T18:22:15.047798] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=18 +[2026-02-20T18:22:15.047800] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:15.047803] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:15.047812] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:15.047815] LOG: [RX FILTER] Raw packet (36 bytes): 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:15.047820] LOG: [RX FILTER] Header: 0x01 | PathLength: 18 | SNR: 11.25 +[2026-02-20T18:22:15.047824] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) +[2026-02-20T18:22:15.047828] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:22:15.047839] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:15.047842] LOG: [RX LOG] Dropped packet hex: 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:15.749402] LOG: [CONN] Frame received (40 bytes): 88 30 c8 01 13 f2 f5 56 ab 5a 7a 7e 75 20 20 20 53 fc 7a 86 e8 7e 6c cc f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c +[2026-02-20T18:22:15.749523] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:15.749558] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:15.749600] LOG: [RX PARSE] RAW Packet (37 bytes): 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:15.749610] LOG: [RX PARSE] Header: 0x01, Route type: 1 +[2026-02-20T18:22:15.749619] LOG: [RX PARSE] Path length offset: 1, Path length: 19 +[2026-02-20T18:22:15.749652] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=19, firstHop=0xf2, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=16 bytes +[2026-02-20T18:22:15.749660] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=19 +[2026-02-20T18:22:15.749673] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:15.749682] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:15.749711] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:15.750134] LOG: [RX FILTER] Raw packet (37 bytes): 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:15.750155] LOG: [RX FILTER] Header: 0x01 | PathLength: 19 | SNR: 12.0 +[2026-02-20T18:22:15.750169] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) +[2026-02-20T18:22:15.750195] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) +[2026-02-20T18:22:15.750256] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype +[2026-02-20T18:22:15.750270] LOG: [RX LOG] Dropped packet hex: 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C +[2026-02-20T18:22:17.602979] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:17.745032] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 11 00 00 00 a4 23 00 00 +[2026-02-20T18:22:17.745169] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:17.745188] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:22:18.329038] LOG: [API QUEUE] Ping flush timer fired +[2026-02-20T18:22:18.329303] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true +[2026-02-20T18:22:18.329320] LOG: [API QUEUE] Uploading 1 items... +[2026-02-20T18:22:18.633612] LOG: [API] POST /wardrive-api.php/wardrive +[2026-02-20T18:22:18.633688] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} +[2026-02-20T18:22:18.633697] LOG: [API] Response (200) in 0.30s: {"success":true,"expires_at":1771640838} +[2026-02-20T18:22:18.633704] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) +[2026-02-20T18:22:18.633713] LOG: [API] Upload batch SUCCESS: 1 items +[2026-02-20T18:22:18.633955] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items +[2026-02-20T18:22:18.633964] LOG: [APP] Upload success: +1 items (total: 78) +[2026-02-20T18:22:20.701500] LOG: [CONN] Frame received (91 bytes): 88 2d ac 15 03 e8 7e db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df +[2026-02-20T18:22:20.701653] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:20.701686] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:20.701732] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:20.701751] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:20.701755] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:22:20.701784] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xdb, SNR=11.25, RSSI=-84, payload=83 bytes +[2026-02-20T18:22:20.701812] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:22:20.701825] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:20.701838] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:20.701893] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:20.701903] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:20.701925] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 +[2026-02-20T18:22:20.701936] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) +[2026-02-20T18:22:20.701941] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:20.701945] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:20.701956] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:20.701964] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:22:20.701967] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:22:20.702069] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:22:20.702657] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." +[2026-02-20T18:22:20.702703] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:22:20.702710] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:22:20.702787] LOG: [RX LOG] Packet heard via last hop: DB, SNR=11.25, path_length=3 +[2026-02-20T18:22:20.702796] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:22:20.702847] LOG: [RX BATCH] First observation for repeater DB: SNR=11.25 +[2026-02-20T18:22:20.702884] LOG: [RX BATCH] Started 30s timeout timer for repeater DB +[2026-02-20T18:22:20.702948] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) +[2026-02-20T18:22:20.702980] LOG: [APP] Immediate RX observation: repeater=DB, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:20.703020] LOG: [APP] Current batch tracking: 0 repeaters: {} +[2026-02-20T18:22:20.703054] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36845,-122.07288 (batch tracking: 1 repeaters, rxCount: 43) +[2026-02-20T18:22:20.703099] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:22:20.703133] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:20.703995] LOG: [CONN] Frame received (1 bytes): 83 +[2026-02-20T18:22:20.704025] LOG: [CONN] Response code: 0x83 (131) +[2026-02-20T18:22:20.704043] LOG: [CONN] Unhandled frame: code=131 (0x83) +[2026-02-20T18:22:21.077843] LOG: [CONN] Frame received (91 bytes): 88 2d a2 15 03 e8 7e ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df +[2026-02-20T18:22:21.077918] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:21.077934] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:21.077961] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.077968] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:21.077973] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:22:21.077982] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xef, SNR=11.25, RSSI=-94, payload=83 bytes +[2026-02-20T18:22:21.077988] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:22:21.077991] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:21.077993] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:21.078021] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:21.078025] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.078033] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 +[2026-02-20T18:22:21.078039] LOG: [RX FILTER] ✓ RSSI OK (-94 < -30) +[2026-02-20T18:22:21.078044] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:21.078051] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:21.078056] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:21.078062] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:22:21.078068] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:22:21.078103] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:22:21.078187] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." +[2026-02-20T18:22:21.078199] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:22:21.078202] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:22:21.078215] LOG: [RX LOG] Packet heard via last hop: EF, SNR=11.25, path_length=3 +[2026-02-20T18:22:21.078218] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:22:21.078227] LOG: [RX BATCH] First observation for repeater EF: SNR=11.25 +[2026-02-20T18:22:21.078233] LOG: [RX BATCH] Started 30s timeout timer for repeater EF +[2026-02-20T18:22:21.078239] LOG: [RX BATCH] Distance check for repeater EF: 0.00m from first observation (threshold=25m) +[2026-02-20T18:22:21.078250] LOG: [APP] Immediate RX observation: repeater=EF, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:21.078257] LOG: [APP] Current batch tracking: 1 repeaters: {DB} +[2026-02-20T18:22:21.078267] LOG: [APP] Created IMMEDIATE RX pin for repeater: EF at 47.36845,-122.07288 (batch tracking: 2 repeaters, rxCount: 44) +[2026-02-20T18:22:21.078275] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:22:21.078284] LOG: [RX LOG] ✅ Observation kept in batch: repeater=EF, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:21.358883] LOG: [CONN] Frame received (91 bytes): 88 30 b4 15 03 e8 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df +[2026-02-20T18:22:21.358907] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:21.358923] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:21.358945] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.358953] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:21.358957] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:22:21.358967] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x6c, SNR=12.0, RSSI=-76, payload=83 bytes +[2026-02-20T18:22:21.358971] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:22:21.358976] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:21.358980] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:21.359] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:21.359006] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.359012] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 12.0 +[2026-02-20T18:22:21.359019] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) +[2026-02-20T18:22:21.359024] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:21.359027] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:21.359034] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:21.359038] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:22:21.359043] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:22:21.359077] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:22:21.359142] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." +[2026-02-20T18:22:21.359150] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:22:21.359157] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:22:21.359205] LOG: [RX LOG] Packet heard via last hop: 6C, SNR=12.0, path_length=3 +[2026-02-20T18:22:21.359208] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:22:21.359213] LOG: [RX BATCH] First observation for repeater 6C: SNR=12.0 +[2026-02-20T18:22:21.359221] LOG: [RX BATCH] Started 30s timeout timer for repeater 6C +[2026-02-20T18:22:21.359227] LOG: [RX BATCH] Distance check for repeater 6C: 0.00m from first observation (threshold=25m) +[2026-02-20T18:22:21.359234] LOG: [APP] Immediate RX observation: repeater=6C, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:21.359450] LOG: [APP] Current batch tracking: 2 repeaters: {DB, EF} +[2026-02-20T18:22:21.359461] LOG: [APP] Created IMMEDIATE RX pin for repeater: 6C at 47.36845,-122.07288 (batch tracking: 3 repeaters, rxCount: 45) +[2026-02-20T18:22:21.359469] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:22:21.359475] LOG: [RX LOG] ✅ Observation kept in batch: repeater=6C, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:21.688232] LOG: [CONN] Frame received (91 bytes): 88 2f b4 15 03 e8 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df +[2026-02-20T18:22:21.688299] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:21.688311] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:21.688335] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.688344] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:21.688347] LOG: [RX PARSE] Path length offset: 1, Path length: 3 +[2026-02-20T18:22:21.688358] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x02, SNR=11.75, RSSI=-76, payload=83 bytes +[2026-02-20T18:22:21.688363] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 +[2026-02-20T18:22:21.688367] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:21.688372] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:21.688393] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:21.688398] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:21.688406] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.75 +[2026-02-20T18:22:21.688412] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) +[2026-02-20T18:22:21.688416] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:21.688419] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:21.688424] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:21.688429] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:22:21.688432] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:22:21.688465] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:22:21.688486] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." +[2026-02-20T18:22:21.688496] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:22:21.688498] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:22:21.688510] LOG: [RX LOG] Packet heard via last hop: 02, SNR=11.75, path_length=3 +[2026-02-20T18:22:21.688513] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:22:21.688521] LOG: [RX BATCH] First observation for repeater 02: SNR=11.75 +[2026-02-20T18:22:21.688527] LOG: [RX BATCH] Started 30s timeout timer for repeater 02 +[2026-02-20T18:22:21.688536] LOG: [RX BATCH] Distance check for repeater 02: 0.00m from first observation (threshold=25m) +[2026-02-20T18:22:21.688544] LOG: [APP] Immediate RX observation: repeater=02, snr=11.75, location=47.36845,-122.07288 +[2026-02-20T18:22:21.688552] LOG: [APP] Current batch tracking: 3 repeaters: {DB, EF, 6C} +[2026-02-20T18:22:21.688558] LOG: [APP] Created IMMEDIATE RX pin for repeater: 02 at 47.36845,-122.07288 (batch tracking: 4 repeaters, rxCount: 46) +[2026-02-20T18:22:21.688571] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:22:21.688579] LOG: [RX LOG] ✅ Observation kept in batch: repeater=02, snr=11.75, location=47.36845,-122.07288 +[2026-02-20T18:22:22.005033] LOG: [CONN] Frame received (92 bytes): 88 30 c9 15 04 e8 7e db cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df +[2026-02-20T18:22:22.005103] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:22.005115] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:22.005139] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 E8 7E DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:22.005147] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:22.005150] LOG: [RX PARSE] Path length offset: 1, Path length: 4 +[2026-02-20T18:22:22.005162] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-55, payload=83 bytes +[2026-02-20T18:22:22.005165] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 +[2026-02-20T18:22:22.005171] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:22.005175] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:22.005196] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:22.005202] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 E8 7E DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF +[2026-02-20T18:22:22.005208] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 +[2026-02-20T18:22:22.005216] LOG: [RX FILTER] ✓ RSSI OK (-55 < -30) +[2026-02-20T18:22:22.005220] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:22.005223] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:22.005230] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:22.005234] LOG: [RX FILTER] Encrypted message: 80 bytes +[2026-02-20T18:22:22.005242] LOG: [CRYPTO] Decrypting message (80 bytes) +[2026-02-20T18:22:22.005273] LOG: [CRYPTO] Decrypted successfully (80 bytes) +[2026-02-20T18:22:22.005350] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." +[2026-02-20T18:22:22.005358] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) +[2026-02-20T18:22:22.005363] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations +[2026-02-20T18:22:22.005373] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 +[2026-02-20T18:22:22.005378] LOG: [RX LOG] ✅ Packet validated and passed filter +[2026-02-20T18:22:22.005385] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 +[2026-02-20T18:22:22.005393] LOG: [RX BATCH] Started 30s timeout timer for repeater CC +[2026-02-20T18:22:22.005402] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) +[2026-02-20T18:22:22.005409] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:22.005416] LOG: [APP] Current batch tracking: 4 repeaters: {DB, EF, 6C, 02} +[2026-02-20T18:22:22.005426] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36845,-122.07288 (batch tracking: 5 repeaters, rxCount: 47) +[2026-02-20T18:22:22.005433] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) +[2026-02-20T18:22:22.005441] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:22.573639] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:22:22.573732] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:22:22.602628] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:22.662658] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c9 30 11 00 00 00 a5 23 00 00 +[2026-02-20T18:22:22.662720] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:22.662731] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:22:23.634634] LOG: [MAP] Refreshing overlay tiles +[2026-02-20T18:22:25.304015] LOG: [CONN] Frame received (95 bytes): 88 2d a3 15 08 e8 7e 75 20 20 75 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d +[2026-02-20T18:22:25.304095] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:25.304110] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:25.304134] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:25.304141] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:25.304145] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:25.304153] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0x6c, SNR=11.25, RSSI=-93, payload=82 bytes +[2026-02-20T18:22:25.304158] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:22:25.304161] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:25.304165] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:25.304187] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:25.304190] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:25.304210] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 11.25 +[2026-02-20T18:22:25.304215] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) +[2026-02-20T18:22:25.304219] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:25.304223] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:25.304226] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:25.304231] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:22:25.304234] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:22:25.304315] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:25.304333] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:25.304414] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:25.304451] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:25.304456] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:25.579469] LOG: [CONN] Frame received (95 bytes): 88 31 bc 15 08 e8 7e 75 20 20 75 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d +[2026-02-20T18:22:25.579555] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:25.579573] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:25.579598] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:25.579605] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:25.579609] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:25.579628] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0x02, SNR=12.25, RSSI=-68, payload=82 bytes +[2026-02-20T18:22:25.579633] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:22:25.579636] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:25.579642] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:25.579667] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:25.579670] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:25.579678] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 +[2026-02-20T18:22:25.579686] LOG: [RX FILTER] ✓ RSSI OK (-68 < -30) +[2026-02-20T18:22:25.579690] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:25.579693] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:25.579699] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:25.579703] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:22:25.579706] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:22:25.579805] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:25.579825] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:25.579907] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:25.579947] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:25.579951] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.009730] LOG: [GPS SERVICE] Position stream fired: lat=47.36856, lon=-122.07275, accuracy=3.8m +[2026-02-20T18:22:26.009826] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:22:26.009848] LOG: [RX BATCH] Checking 5 active batch(es) for distance trigger +[2026-02-20T18:22:26.009860] LOG: [RX BATCH] Distance check for repeater DB: 16.31m from first observation (threshold=25m) +[2026-02-20T18:22:26.009865] LOG: [RX BATCH] Distance check for repeater EF: 16.31m from first observation (threshold=25m) +[2026-02-20T18:22:26.009888] LOG: [RX BATCH] Distance check for repeater 6C: 16.31m from first observation (threshold=25m) +[2026-02-20T18:22:26.009893] LOG: [RX BATCH] Distance check for repeater 02: 16.31m from first observation (threshold=25m) +[2026-02-20T18:22:26.009899] LOG: [RX BATCH] Distance check for repeater CC: 16.31m from first observation (threshold=25m) +[2026-02-20T18:22:26.009906] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:22:26.202046] LOG: [CONN] Frame received (95 bytes): 88 30 ac 15 08 e8 7e 75 20 20 75 7e db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d +[2026-02-20T18:22:26.202110] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:26.202124] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:26.202147] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.202157] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:26.202160] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:26.202170] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xdb, SNR=12.0, RSSI=-84, payload=82 bytes +[2026-02-20T18:22:26.202174] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:22:26.202177] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:26.202182] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:26.202204] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:26.202207] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.202215] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.0 +[2026-02-20T18:22:26.202221] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) +[2026-02-20T18:22:26.202225] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:26.202228] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:26.202231] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:26.202237] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:22:26.202240] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:22:26.202308] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:26.202325] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:26.202403] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:26.202439] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:26.202443] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.598291] LOG: [CONN] Frame received (95 bytes): 88 30 c7 15 08 e8 7e 75 20 20 75 7e cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d +[2026-02-20T18:22:26.598316] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:26.598333] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:26.598355] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.598362] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:26.598366] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:26.598374] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=82 bytes +[2026-02-20T18:22:26.598380] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:22:26.598383] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:26.598387] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:26.598413] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:26.598416] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:26.598423] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.0 +[2026-02-20T18:22:26.598427] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) +[2026-02-20T18:22:26.598432] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:26.598437] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:26.598440] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:26.598445] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:22:26.598450] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:22:26.598538] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:26.598597] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:26.598669] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:26.598719] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:26.598725] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:27.221806] LOG: [CONN] Frame received (95 bytes): 88 2f a6 15 08 e8 7e 75 20 20 75 7e ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d +[2026-02-20T18:22:27.221878] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:27.221894] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:27.221920] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:27.221927] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:27.221930] LOG: [RX PARSE] Path length offset: 1, Path length: 8 +[2026-02-20T18:22:27.221941] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xef, SNR=11.75, RSSI=-90, payload=82 bytes +[2026-02-20T18:22:27.221946] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 +[2026-02-20T18:22:27.221949] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:27.221954] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:27.221976] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:27.221979] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:27.221989] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 11.75 +[2026-02-20T18:22:27.221995] LOG: [RX FILTER] ✓ RSSI OK (-90 < -30) +[2026-02-20T18:22:27.222] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:27.222003] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:27.222007] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:27.222014] LOG: [RX FILTER] Encrypted message: 79 bytes +[2026-02-20T18:22:27.222018] LOG: [CRYPTO] Decrypting message (79 bytes) +[2026-02-20T18:22:27.222097] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:27.222116] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:27.222206] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:27.222242] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:27.222248] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D +[2026-02-20T18:22:27.602631] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... +[2026-02-20T18:22:27.602726] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:27.735993] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 +[2026-02-20T18:22:27.736047] LOG: [CONN] Response code: 0x0c (12) +[2026-02-20T18:22:27.736052] LOG: [CONN] Battery response has 8 extra bytes (ignoring) +[2026-02-20T18:22:27.736060] LOG: [CONN] Battery updated: 4062mV (89%) +[2026-02-20T18:22:27.791318] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff a6 2f 11 00 00 00 a7 23 00 00 +[2026-02-20T18:22:27.791394] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:27.791405] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:22:30.587495] LOG: [CONN] Frame received (98 bytes): 88 2f b1 15 0c e8 7e 75 20 20 20 53 e0 7e 3e 32 db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 +[2026-02-20T18:22:30.587668] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:30.587794] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:30.587823] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:30.587830] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:30.587834] LOG: [RX PARSE] Path length offset: 1, Path length: 12 +[2026-02-20T18:22:30.587845] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-79, payload=81 bytes +[2026-02-20T18:22:30.587849] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 +[2026-02-20T18:22:30.587854] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:30.587858] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:30.587941] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:30.587946] LOG: [RX FILTER] Raw packet (95 bytes): 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:30.587953] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 +[2026-02-20T18:22:30.587962] LOG: [RX FILTER] ✓ RSSI OK (-79 < -30) +[2026-02-20T18:22:30.587965] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:30.587968] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:30.587974] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:30.587978] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:22:30.587981] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:22:30.588108] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:30.588128] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:30.588206] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:30.588244] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:30.588248] LOG: [RX LOG] Dropped packet hex: 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:30.991955] LOG: [CONN] Frame received (99 bytes): 88 30 ba 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 +[2026-02-20T18:22:30.992066] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:30.992092] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:30.992147] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:30.992162] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:30.992169] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:22:30.992192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0x02, SNR=12.0, RSSI=-70, payload=81 bytes +[2026-02-20T18:22:30.992201] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:22:30.992208] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:30.992217] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:30.992269] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:30.992280] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:30.992295] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.0 +[2026-02-20T18:22:30.992308] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) +[2026-02-20T18:22:30.992315] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:30.992321] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:30.992333] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:30.992342] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:22:30.992348] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:22:30.992477] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:30.992509] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:30.992647] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:30.992731] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:30.992738] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.363647] LOG: [CONN] Frame received (99 bytes): 88 2b a7 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 +[2026-02-20T18:22:31.363690] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:31.363720] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:31.363774] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.363787] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:31.363794] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:22:31.363823] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0x6c, SNR=10.75, RSSI=-89, payload=81 bytes +[2026-02-20T18:22:31.363832] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:22:31.363838] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:31.363847] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:31.363898] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:31.363908] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.363921] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 10.75 +[2026-02-20T18:22:31.363933] LOG: [RX FILTER] ✓ RSSI OK (-89 < -30) +[2026-02-20T18:22:31.363940] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:31.363946] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:31.363955] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:31.363963] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:22:31.363969] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:22:31.364103] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:31.364217] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:31.364381] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:31.364467] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:31.364473] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.791236] LOG: [CONN] Frame received (99 bytes): 88 2f a6 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 +[2026-02-20T18:22:31.791350] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:31.791373] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:31.791427] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.791442] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:31.791448] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:22:31.791467] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0xef, SNR=11.75, RSSI=-90, payload=81 bytes +[2026-02-20T18:22:31.791476] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:22:31.791484] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:31.791492] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:31.791547] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:31.791556] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:31.791568] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 11.75 +[2026-02-20T18:22:31.791581] LOG: [RX FILTER] ✓ RSSI OK (-90 < -30) +[2026-02-20T18:22:31.791587] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:31.791601] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:31.791608] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:31.791615] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:22:31.791624] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:22:31.791750] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:31.791781] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:31.791921] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:31.792] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:31.792007] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:32.443180] LOG: [CONN] Frame received (99 bytes): 88 2b b7 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 +[2026-02-20T18:22:32.443299] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:32.443318] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:32.443357] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:32.443368] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:32.443374] LOG: [RX PARSE] Path length offset: 1, Path length: 13 +[2026-02-20T18:22:32.443389] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0xcc, SNR=10.75, RSSI=-73, payload=81 bytes +[2026-02-20T18:22:32.443397] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 +[2026-02-20T18:22:32.443401] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:32.443444] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:32.443481] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:32.443488] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:32.443498] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 10.75 +[2026-02-20T18:22:32.443508] LOG: [RX FILTER] ✓ RSSI OK (-73 < -30) +[2026-02-20T18:22:32.443513] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:32.443517] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:32.443525] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:32.443531] LOG: [RX FILTER] Encrypted message: 78 bytes +[2026-02-20T18:22:32.443535] LOG: [CRYPTO] Decrypting message (78 bytes) +[2026-02-20T18:22:32.443638] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:32.443661] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:32.443775] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:32.443837] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:32.443842] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 +[2026-02-20T18:22:32.602673] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:32.651258] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff b7 2b 11 00 00 00 a9 23 00 00 +[2026-02-20T18:22:32.651332] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:32.651341] LOG: [CONN] Noise floor updated: -120dBm +[2026-02-20T18:22:34.950719] LOG: [CONN] Frame received (99 bytes): 88 2f a8 15 0f e8 7e 75 20 20 20 20 20 75 ee 66 6a 17 1f db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 +[2026-02-20T18:22:34.950805] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:34.950823] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:34.950867] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:34.950878] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:34.950885] LOG: [RX PARSE] Path length offset: 1, Path length: 15 +[2026-02-20T18:22:34.950897] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-88, payload=79 bytes +[2026-02-20T18:22:34.950906] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 +[2026-02-20T18:22:34.950911] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:34.950917] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:34.950975] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:34.950980] LOG: [RX FILTER] Raw packet (96 bytes): 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:34.950991] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 11.75 +[2026-02-20T18:22:34.950998] LOG: [RX FILTER] ✓ RSSI OK (-88 < -30) +[2026-02-20T18:22:34.951007] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:34.951012] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:34.951018] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:34.951028] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:22:34.951032] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:22:34.951179] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:34.951262] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:34.951387] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:34.951454] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:34.951460] LOG: [RX LOG] Dropped packet hex: 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.471704] LOG: [CONN] Frame received (98 bytes): 88 29 b5 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 +[2026-02-20T18:22:35.471767] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:35.471781] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:35.471808] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.471815] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:35.471819] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:22:35.471831] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x02, SNR=10.25, RSSI=-75, payload=79 bytes +[2026-02-20T18:22:35.471853] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:22:35.471856] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:35.471861] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:35.471889] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:35.471893] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.471902] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 10.25 +[2026-02-20T18:22:35.471907] LOG: [RX FILTER] ✓ RSSI OK (-75 < -30) +[2026-02-20T18:22:35.471914] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:35.471917] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:35.471920] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:35.471926] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:22:35.471929] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:22:35.472004] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:35.472022] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:35.472106] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:35.472147] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:35.472152] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.993157] LOG: [CONN] Frame received (98 bytes): 88 32 ab 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 +[2026-02-20T18:22:35.993226] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:35.993238] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:35.993271] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.993279] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:35.993283] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:22:35.993298] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x6c, SNR=12.5, RSSI=-85, payload=79 bytes +[2026-02-20T18:22:35.993303] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:22:35.993310] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:35.993314] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:35.993344] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:35.993351] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:35.993358] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.5 +[2026-02-20T18:22:35.993366] LOG: [RX FILTER] ✓ RSSI OK (-85 < -30) +[2026-02-20T18:22:35.993370] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:35.993374] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:35.993381] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:35.993386] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:22:35.993389] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:22:35.993466] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:35.993485] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:35.993571] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:35.993617] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:35.993622] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:36.492060] LOG: [CONN] Frame received (98 bytes): 88 31 bc 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 +[2026-02-20T18:22:36.492087] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:36.492106] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:36.492134] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:36.492141] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:36.492145] LOG: [RX PARSE] Path length offset: 1, Path length: 14 +[2026-02-20T18:22:36.492154] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xcc, SNR=12.25, RSSI=-68, payload=79 bytes +[2026-02-20T18:22:36.492172] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 +[2026-02-20T18:22:36.492175] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:36.492177] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:36.492204] LOG: [RX FILTER] ========== VALIDATING PACKET ========== +[2026-02-20T18:22:36.492207] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:36.492215] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.25 +[2026-02-20T18:22:36.492219] LOG: [RX FILTER] ✓ RSSI OK (-68 < -30) +[2026-02-20T18:22:36.492224] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) +[2026-02-20T18:22:36.492228] LOG: [RX FILTER] Channel hash: 0x81 +[2026-02-20T18:22:36.492232] LOG: [RX FILTER] ✓ Channel matched: #wardriving +[2026-02-20T18:22:36.492238] LOG: [RX FILTER] Encrypted message: 76 bytes +[2026-02-20T18:22:36.492243] LOG: [CRYPTO] Decrypting message (76 bytes) +[2026-02-20T18:22:36.492317] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:36.492375] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short +[2026-02-20T18:22:36.492454] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) +#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) +#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) +#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) +#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) +#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) +#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) +#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) +#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) +#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) +#10 _DelayedData.perform (dart:async/stream_impl.dart:573) +#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) +#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) +#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) +#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) + +[2026-02-20T18:22:36.492547] LOG: [RX LOG] ❌ Packet dropped: validation error +[2026-02-20T18:22:36.492553] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 +[2026-02-20T18:22:37.574731] LOG: [API QUEUE] Batch timer fired (15s interval) +[2026-02-20T18:22:37.574881] LOG: [API QUEUE] Upload skipped: queue empty +[2026-02-20T18:22:37.602820] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:37.784831] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bc 31 11 00 00 00 aa 23 00 00 +[2026-02-20T18:22:37.784985] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:37.785006] LOG: [CONN] Noise floor updated: -118dBm +[2026-02-20T18:22:42.602880] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:42.793461] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff bc 31 11 00 00 00 aa 23 00 00 +[2026-02-20T18:22:42.793564] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:42.793583] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:22:43.326973] LOG: [ACTIVE MODE] Auto ping timer fired +[2026-02-20T18:22:43.327149] LOG: [ACTIVE MODE] Sending auto ping +[2026-02-20T18:22:43.327166] LOG: [PING] sendTxPing called (manual=false) +[2026-02-20T18:22:43.327209] LOG: [PING] Created TxPing, ready for echo tracking +[2026-02-20T18:22:43.327270] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36856, -122.07275 [0.3w]" +[2026-02-20T18:22:43.327280] LOG: [TX LOG] Starting echo tracking +[2026-02-20T18:22:43.327292] LOG: [TX LOG] Payload: "@[MapperBot] 47.36856, -122.07275 [0.3w]" +[2026-02-20T18:22:43.327303] LOG: [TX LOG] Channel: 2, Hash: 0x81 +[2026-02-20T18:22:43.327317] LOG: [TX LOG] Echo tracking window started (5s) +[2026-02-20T18:22:43.327332] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false +[2026-02-20T18:22:43.327342] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled +[2026-02-20T18:22:43.327360] LOG: [CONN] Sending ping: @[MapperBot] 47.36856, -122.07275 [0.3w] +[2026-02-20T18:22:43.451203] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:22:43.451266] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:22:43.451271] LOG: [CONN] Received OK response +[2026-02-20T18:22:44.157633] LOG: [CONN] Frame received (73 bytes): 88 31 ce 15 01 cc 81 ad b5 13 31 c2 c5 a9 1b dc 27 cd 01 62 37 af 6e 29 c2 c9 f6 de 44 d6 aa 36 77 63 ab f0 f7 c0 d4 4e 42 63 5a 16 58 46 8d 99 8f e1 c7 bb 11 b5 9c eb c7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 +[2026-02-20T18:22:44.157740] LOG: [CONN] Response code: 0x88 (136) +[2026-02-20T18:22:44.157761] LOG: [RX PARSE] Starting metadata parsing +[2026-02-20T18:22:44.157803] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 AD B5 13 31 C2 C5 A9 1B DC 27 CD 01 62 37 AF 6E 29 C2 C9 F6 DE 44 D6 AA 36 77 63 AB F0 F7 C0 D4 4E 42 63 5A 16 58 46 8D 99 8F E1 C7 BB 11 B5 9C EB C7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 +[2026-02-20T18:22:44.157834] LOG: [RX PARSE] Header: 0x15, Route type: 1 +[2026-02-20T18:22:44.157840] LOG: [RX PARSE] Path length offset: 1, Path length: 1 +[2026-02-20T18:22:44.157920] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-50, payload=67 bytes +[2026-02-20T18:22:44.157929] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 +[2026-02-20T18:22:44.157938] LOG: [UNIFIED RX] TX tracking active - checking for echo +[2026-02-20T18:22:44.157946] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-50 +[2026-02-20T18:22:44.157952] LOG: [TX LOG] Header validation passed: 0x15 +[2026-02-20T18:22:44.157961] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:22:44.157968] LOG: [UNIFIED RX] RX wardriving active - logging observation +[2026-02-20T18:22:44.157973] LOG: [RX LOG] Processing packet for passive logging +[2026-02-20T18:22:44.157983] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping +[2026-02-20T18:22:46.453022] LOG: [PING] Ping sent successfully +[2026-02-20T18:22:47.468786] LOG: [HEARTBEAT] Heartbeat mode disabled +[2026-02-20T18:22:47.468843] LOG: [PING] Force disabling auto-ping +[2026-02-20T18:22:47.468849] LOG: [DISC] Stopping discovery mode +[2026-02-20T18:22:47.471543] LOG: [WAKELOCK] Screen wake lock disabled +[2026-02-20T18:22:47.471663] LOG: [GRAPH] Ended session: 22:48, 273 samples, 82 markers +[2026-02-20T18:22:47.472795] LOG: [BACKGROUND] Stopping background service +[2026-02-20T18:22:47.472844] LOG: [BACKGROUND] Background service stopped +[2026-02-20T18:22:47.472850] LOG: [TIMER] Cooldown timer stopped +[2026-02-20T18:22:47.472853] LOG: [RX LOG] Stopping passive RX wardriving: trigger=disconnect +[2026-02-20T18:22:47.472859] LOG: [RX BATCH] Flushing all repeaters, trigger=disconnect, active_repeaters=5 +[2026-02-20T18:22:47.472867] LOG: [RX BATCH] Flushing repeater DB +[2026-02-20T18:22:47.472870] LOG: [RX BATCH] Cleared timeout timer for repeater DB +[2026-02-20T18:22:47.472880] LOG: [RX BATCH] Posting repeater DB: snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472884] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:22:47.472890] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472897] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 11.25 <= pin 11.25 +[2026-02-20T18:22:47.472901] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=4 +[2026-02-20T18:22:47.472907] LOG: [APP] Added RX log entry: repeater=DB, snr=11.25, pathLen=3 +[2026-02-20T18:22:47.472918] LOG: [API QUEUE] Timers stopped on disconnect +[2026-02-20T18:22:47.472924] LOG: [API QUEUE] Clearing 1 items on disconnect (queue: 0, rxBuffer: 1) +[2026-02-20T18:22:47.472931] LOG: [RX BATCH] Repeater DB removed from buffer +[2026-02-20T18:22:47.472934] LOG: [RX BATCH] Flushing repeater EF +[2026-02-20T18:22:47.472938] LOG: [RX BATCH] Cleared timeout timer for repeater EF +[2026-02-20T18:22:47.472943] LOG: [RX BATCH] Posting repeater EF: snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472945] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:22:47.472951] LOG: [APP] Finalized RX entry (best SNR): repeater=EF, snr=11.25, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472955] LOG: [APP] RX pin SNR unchanged for repeater=EF: batch best 11.25 <= pin 11.25 +[2026-02-20T18:22:47.472958] LOG: [APP] Cleared batch tracking for EF: wasPresent=true, remaining=3 +[2026-02-20T18:22:47.472964] LOG: [APP] Added RX log entry: repeater=EF, snr=11.25, pathLen=3 +[2026-02-20T18:22:47.472972] LOG: [RX BATCH] Repeater EF removed from buffer +[2026-02-20T18:22:47.472975] LOG: [RX BATCH] Flushing repeater 6C +[2026-02-20T18:22:47.472977] LOG: [RX BATCH] Cleared timeout timer for repeater 6C +[2026-02-20T18:22:47.472985] LOG: [RX BATCH] Posting repeater 6C: snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472987] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:22:47.472992] LOG: [APP] Finalized RX entry (best SNR): repeater=6C, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:47.472997] LOG: [APP] RX pin SNR unchanged for repeater=6C: batch best 12.00 <= pin 12.00 +[2026-02-20T18:22:47.473] LOG: [APP] Cleared batch tracking for 6C: wasPresent=true, remaining=2 +[2026-02-20T18:22:47.473021] LOG: [APP] Added RX log entry: repeater=6C, snr=12.0, pathLen=3 +[2026-02-20T18:22:47.473042] LOG: [RX BATCH] Repeater 6C removed from buffer +[2026-02-20T18:22:47.473046] LOG: [RX BATCH] Flushing repeater 02 +[2026-02-20T18:22:47.473051] LOG: [RX BATCH] Cleared timeout timer for repeater 02 +[2026-02-20T18:22:47.473055] LOG: [RX BATCH] Posting repeater 02: snr=11.75, location=47.36845,-122.07288 +[2026-02-20T18:22:47.473058] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:22:47.473064] LOG: [APP] Finalized RX entry (best SNR): repeater=02, snr=11.75, location=47.36845,-122.07288 +[2026-02-20T18:22:47.473069] LOG: [APP] RX pin SNR unchanged for repeater=02: batch best 11.75 <= pin 11.75 +[2026-02-20T18:22:47.473074] LOG: [APP] Cleared batch tracking for 02: wasPresent=true, remaining=1 +[2026-02-20T18:22:47.473079] LOG: [APP] Added RX log entry: repeater=02, snr=11.75, pathLen=3 +[2026-02-20T18:22:47.473086] LOG: [RX BATCH] Repeater 02 removed from buffer +[2026-02-20T18:22:47.473089] LOG: [RX BATCH] Flushing repeater CC +[2026-02-20T18:22:47.473094] LOG: [RX BATCH] Cleared timeout timer for repeater CC +[2026-02-20T18:22:47.473098] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:47.473101] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== +[2026-02-20T18:22:47.473108] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.36845,-122.07288 +[2026-02-20T18:22:47.473111] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 +[2026-02-20T18:22:47.473116] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 +[2026-02-20T18:22:47.473121] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 +[2026-02-20T18:22:47.473129] LOG: [RX BATCH] Repeater CC removed from buffer +[2026-02-20T18:22:47.473133] LOG: [RX BATCH] All repeaters flushed: 5 total +[2026-02-20T18:22:47.473356] LOG: [APP] Releasing API session +[2026-02-20T18:22:47.602828] LOG: [CONN] Fetching noise floor... +[2026-02-20T18:22:47.654284] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 97 90 11 00 00 00 aa 23 00 00 +[2026-02-20T18:22:47.654398] LOG: [CONN] Response code: 0x18 (24) +[2026-02-20T18:22:47.654413] LOG: [CONN] Noise floor updated: -119dBm +[2026-02-20T18:22:48.327946] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:22:48.913528] LOG: [API] POST /wardrive-api.php/auth +[2026-02-20T18:22:48.913563] LOG: [API] Request: {"reason":"disconnect"} +[2026-02-20T18:22:48.913570] LOG: [API] Response (200) in 1.44s: {"success":true,"disconnected":true} +[2026-02-20T18:22:48.913575] LOG: [API] Session cleared +[2026-02-20T18:22:48.913579] LOG: [APP] API session released successfully +[2026-02-20T18:22:49.065339] LOG: [CONN] Frame received (1 bytes): 00 +[2026-02-20T18:22:49.065644] LOG: [CONN] Response code: 0x00 (0) +[2026-02-20T18:22:49.065653] LOG: [CONN] Received OK response +[2026-02-20T18:22:49.066297] LOG: [CHANNEL] Deleting channel at index 2 +[2026-02-20T18:22:49.120917] LOG: [CHANNEL] Channel deleted successfully +[2026-02-20T18:22:49.120982] LOG: [UNIFIED RX] Disposing unified handler +[2026-02-20T18:22:49.120986] LOG: [UNIFIED RX] Stopping unified RX listening +[2026-02-20T18:22:49.120992] LOG: [UNIFIED RX] ✅ Unified listening stopped +[2026-02-20T18:22:49.120997] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) +[2026-02-20T18:22:49.121] LOG: [RX LOG] Disposing RX Logger +[2026-02-20T18:22:49.122983] LOG: [CONN] Disconnecting +[2026-02-20T18:22:49.122997] LOG: [CONN] Stopped noise floor polling +[2026-02-20T18:22:49.123] LOG: [CONN] Stopped battery polling +[2026-02-20T18:22:49.128674] LOG: [BLE] Connection state changed: BluetoothConnectionState.disconnected +[2026-02-20T18:22:49.128733] LOG: [CONN] Step: ConnectionStep.disconnected +[2026-02-20T18:22:49.128738] LOG: [CONN] Disconnected successfully +[2026-02-20T18:22:49.128749] LOG: [HEARTBEAT] Heartbeat mode disabled +[2026-02-20T18:22:49.128752] LOG: [CONN] Heartbeat disabled due to BLE disconnect +[2026-02-20T18:22:49.128777] LOG: [API QUEUE] Timers stopped on disconnect +[2026-02-20T18:22:49.128790] LOG: [CONN] Stopped noise floor polling +[2026-02-20T18:22:49.128793] LOG: [CONN] Stopped battery polling +[2026-02-20T18:22:49.128799] LOG: [DISC] Stopping discovery mode +[2026-02-20T18:22:49.128920] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:22:49.128935] LOG: [CHANNEL] Clearing regional channels +[2026-02-20T18:22:49.128952] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:22:49.129250] LOG: [APP] Saved preferences +[2026-02-20T18:35:06.841467] LOG: [GPS SERVICE] Position stream fired: lat=47.36841, lon=-122.07247, accuracy=11.4m +[2026-02-20T18:35:06.841540] LOG: [HIVE] Opening box "user_preferences"... +[2026-02-20T18:35:06.841570] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone +[2026-02-20T18:35:06.841574] LOG: [GEOFENCE] checkZoneStatus() called +[2026-02-20T18:35:06.841588] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked +[2026-02-20T18:35:06.841599] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) +[2026-02-20T18:35:06.841604] LOG: [GEOFENCE] Making API call to check zone at 47.36841, -122.07247 (accuracy: 11.4m) +[2026-02-20T18:35:06.842569] LOG: [HIVE] Box "user_preferences" opened successfully +[2026-02-20T18:35:06.900196] LOG: [APP] App resumed from background +[2026-02-20T18:35:07.201989] LOG: [API] POST /wardrive-api.php/status +[2026-02-20T18:35:07.202025] LOG: [API] Request: {"lat":47.3684066,"lng":-122.0724722,"accuracy_m":11.39900016784668,"ver":"APP-1771555184","timestamp":1771641306} +[2026-02-20T18:35:07.202029] LOG: [API] Response (200) in 0.36s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":14,"slots_max":15}} +[2026-02-20T18:35:07.202036] LOG: [GEOFENCE] API response received: valid +[2026-02-20T18:35:07.202043] LOG: [GEOFENCE] In zone: Seattle, US (SEA) +[2026-02-20T18:35:07.202045] LOG: [MAP] Repeaters already loaded for zone: SEA +[2026-02-20T18:35:07.202051] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA +[2026-02-20T18:39:04.130110] LOG: [APP] App resumed from background +[2026-02-20T19:21:20.992957] LOG: [APP] App resumed from background +[2026-02-20T19:21:53.358683] LOG: [DEBUG] Rotating log file for upload... + +=== Log rotated for upload: 2026-02-20T19:21:53.358790 === diff --git a/lib/services/meshcore/rx_logger.dart b/lib/services/meshcore/rx_logger.dart index c20f675..aa8a116 100644 --- a/lib/services/meshcore/rx_logger.dart +++ b/lib/services/meshcore/rx_logger.dart @@ -78,31 +78,33 @@ class RxLogger { return false; } - // CARpeater pass-through: check firstHop against carpeaterPrefix - final firstHopId = metadata.firstHop!; - final firstHopHex = firstHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); bool carpeaterStripped = false; String repeaterId; double? reportedSnr = metadata.snr; int? reportedRssi = metadata.rssi; - if (carpeaterPrefix != null && firstHopHex == carpeaterPrefix!.toUpperCase()) { + // Extract LAST hop from path (the repeater that directly delivered to us) + // Mask to last byte only (0xFF) for consistent 2-character display + final lastHopId = metadata.lastHop! & 0xFF; + final lastHopHex = lastHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + + // CARpeater check: the carpeater is co-located with us, so it only + // appears as the last hop (the delivery repeater) on RX packets + if (carpeaterPrefix != null && lastHopHex == carpeaterPrefix!.toUpperCase()) { if (metadata.pathLength < 2) { debugLog('[RX LOG] CARpeater pass-through: single-hop, dropping'); return false; } - // Multi-hop: strip CARpeater, report underlying repeater (pathBytes[1]) - final underlyingHopId = metadata.pathBytes[1] & 0xFF; + // Second-to-last hop = the real repeater that forwarded to our carpeater + final secondToLastIdx = metadata.pathLength - 2; + final underlyingHopId = metadata.pathBytes[secondToLastIdx] & 0xFF; repeaterId = underlyingHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); carpeaterStripped = true; reportedSnr = null; reportedRssi = null; - debugLog('[RX LOG] CARpeater pass-through: stripped $firstHopHex, reporting underlying repeater $repeaterId'); + debugLog('[RX LOG] CARpeater pass-through: stripped $lastHopHex, reporting underlying repeater $repeaterId'); } else { - // Normal path: extract LAST hop from path (the repeater that directly delivered to us) - // Mask to last byte only (0xFF) for consistent 2-character display - final lastHopId = metadata.lastHop! & 0xFF; - repeaterId = lastHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + repeaterId = lastHopHex; } // Get current GPS location From 8c9f7c973b7739c5361ad9228403f01a4748a3f0 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Thu, 26 Feb 2026 19:04:16 -0500 Subject: [PATCH 15/57] Debug logging is now enabled by default on all builds (not just dev builds), and the user's toggle preference is persisted across app restarts via Hive --- debug/47.34022, -122.22241.txt | 11914 ------------------------ lib/main.dart | 5 +- lib/providers/app_state_provider.dart | 47 +- lib/screens/settings_screen.dart | 4 +- lib/utils/debug_logger_stub.dart | 4 +- 5 files changed, 40 insertions(+), 11934 deletions(-) delete mode 100644 debug/47.34022, -122.22241.txt diff --git a/debug/47.34022, -122.22241.txt b/debug/47.34022, -122.22241.txt deleted file mode 100644 index 02810eb..0000000 --- a/debug/47.34022, -122.22241.txt +++ /dev/null @@ -1,11914 +0,0 @@ -=== MeshMapper Debug Log Started: 2026-02-20T17:23:11.248704 === - -[2026-02-20T17:23:11.249183] LOG: [APP] MeshMapper starting... -[2026-02-20T17:23:11.268604] LOG: [APP] Hive initialized -[2026-02-20T17:23:11.270718] LOG: [APP] Initial theme mode: dark -[2026-02-20T17:23:11.270737] LOG: [APP] Noise floor session adapters registered -[2026-02-20T17:23:11.270739] LOG: [APP] Requesting permissions... -[2026-02-20T17:23:11.271203] LOG: [APP] Permission.notification: PermissionStatus.granted -[2026-02-20T17:23:11.271207] LOG: [APP] Permission.bluetoothScan: PermissionStatus.granted -[2026-02-20T17:23:11.271208] LOG: [APP] Permission.bluetoothConnect: PermissionStatus.granted -[2026-02-20T17:23:11.271209] LOG: [BACKGROUND] Checking for orphaned service from previous session -[2026-02-20T17:23:11.271212] LOG: [BACKGROUND] Initializing background service -[2026-02-20T17:23:11.271754] LOG: [BACKGROUND] Service unexpectedly running after configure(), stopping it -[2026-02-20T17:23:11.271762] LOG: [BACKGROUND] Background service initialized -[2026-02-20T17:23:11.271933] LOG: [INIT] AppStateProvider initialization starting... -[2026-02-20T17:23:11.271981] LOG: [INIT] Development build detected (APP-1771555184), auto-enabling debug logs -[2026-02-20T17:23:11.287313] LOG: [CHANNEL] Initializing Public channel only -[2026-02-20T17:23:11.287333] LOG: [CHANNEL] Public channel initialized (hash=17) -[2026-02-20T17:23:11.287335] LOG: [APP] Channel service initialized (Public channel only) -[2026-02-20T17:23:11.287336] LOG: [INIT] Initializing API queue service... -[2026-02-20T17:23:11.287337] LOG: [API QUEUE] init() starting... -[2026-02-20T17:23:11.287338] LOG: [API QUEUE] Checking adapter registration... -[2026-02-20T17:23:11.287339] LOG: [API QUEUE] Registering ApiQueueItemAdapter... -[2026-02-20T17:23:11.287342] LOG: [API QUEUE] Adapter check complete -[2026-02-20T17:23:11.287343] LOG: [API QUEUE] Opening Hive box "api_queue"... -[2026-02-20T17:23:11.287632] LOG: [DISCLOSURE] Already shown, skipping -[2026-02-20T17:23:11.427066] LOG: [API QUEUE] Hive box "api_queue" opened successfully -[2026-02-20T17:23:11.427082] LOG: [API QUEUE] Starting batch timer... -[2026-02-20T17:23:11.427084] LOG: [API QUEUE] init() complete -[2026-02-20T17:23:11.427086] LOG: [INIT] API queue service initialized -[2026-02-20T17:23:11.427101] LOG: [OFFLINE] Initialized with 0 stored sessions -[2026-02-20T17:23:11.446673] LOG: [HIVE] Opening typed box "noise_floor_sessions"... -[2026-02-20T17:23:11.462480] LOG: [HIVE] Typed box "noise_floor_sessions" opened successfully -[2026-02-20T17:23:11.462568] LOG: [GRAPH] Loaded 1 stored noise floor sessions -[2026-02-20T17:23:11.462571] LOG: [HIVE] Opening box "remembered_device"... -[2026-02-20T17:23:11.464016] LOG: [HIVE] Box "remembered_device" opened successfully -[2026-02-20T17:23:11.464134] LOG: [APP] Loaded remembered device: MeshCore-Cozmo -[2026-02-20T17:23:11.464138] LOG: [INIT] Loading preferences... -[2026-02-20T17:23:11.464140] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:11.464151] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:11.464159] LOG: [APP] Loaded preferences: interval=30s, ignoreCarpeater=true, ignoreRepeaterId=CC -[2026-02-20T17:23:11.464161] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:11.464163] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:11.464165] LOG: [APP] Loaded antenna preferences for 1 device(s) -[2026-02-20T17:23:11.464167] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:11.464169] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:11.464175] LOG: [GPS] Loaded last position: 47.3580211, -122.1619081 -[2026-02-20T17:23:11.464176] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:11.464178] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:11.464181] LOG: [APP] Loaded last connected device: Cozmo -[2026-02-20T17:23:11.464182] LOG: [INIT] Setting up Bluetooth adapter state listener... -[2026-02-20T17:23:11.464190] LOG: [INIT] Setting up BLE connection listener... -[2026-02-20T17:23:11.464192] LOG: [INIT] Setting up GPS status listener... -[2026-02-20T17:23:11.464195] LOG: [INIT] Initial GPS status: GpsStatus.permissionDenied -[2026-02-20T17:23:11.464196] LOG: [INIT] Setting up GPS position listener... -[2026-02-20T17:23:11.464198] LOG: [INIT] GPS position listener attached to stream -[2026-02-20T17:23:11.464199] LOG: [INIT] Starting GPS service... -[2026-02-20T17:23:11.464201] LOG: [GPS] startWatching() called, current status: GpsStatus.permissionDenied -[2026-02-20T17:23:11.482217] LOG: [MAP] Initial zoom to last known position -[2026-02-20T17:23:11.489490] LOG: [BLE] Adapter state changed: BluetoothAdapterState.on -[2026-02-20T17:23:11.497466] LOG: [GPS] Location services check: enabled=true -[2026-02-20T17:23:11.497826] LOG: [GPS] Permission check: LocationPermission.whileInUse (hasPermission=true) -[2026-02-20T17:23:11.497829] LOG: [GPS] Starting position stream listener... -[2026-02-20T17:23:11.497832] LOG: [GPS SERVICE] Status update: GpsStatus.permissionDenied → GpsStatus.searching -[2026-02-20T17:23:11.497856] LOG: [GPS] Requesting initial position (15s timeout)... -[2026-02-20T17:23:11.497906] LOG: [GPS] Status changed: GpsStatus.permissionDenied → GpsStatus.searching -[2026-02-20T17:23:13.109098] LOG: [GPS SERVICE] Position stream fired: lat=47.33787, lon=-122.22475, accuracy=11.1m -[2026-02-20T17:23:13.109121] LOG: [GPS SERVICE] Status update: GpsStatus.searching → GpsStatus.locked -[2026-02-20T17:23:13.109128] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:13.109134] LOG: [GEOFENCE] First GPS lock, triggering zone check -[2026-02-20T17:23:13.109135] LOG: [GEOFENCE] checkZoneStatus() called -[2026-02-20T17:23:13.109136] LOG: [GEOFENCE] Pre-check state: inZone=null, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.searching -[2026-02-20T17:23:13.109138] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=null) -[2026-02-20T17:23:13.109140] LOG: [GEOFENCE] Making API call to check zone at 47.33787, -122.22475 (accuracy: 11.1m) -[2026-02-20T17:23:13.109265] LOG: [GPS] Status changed: GpsStatus.searching → GpsStatus.locked -[2026-02-20T17:23:13.109267] LOG: [GPS] GPS lock acquired - zone check should trigger on first position -[2026-02-20T17:23:13.109269] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:13.109798] LOG: [GPS] Initial position acquired: 47.33787, -122.22475 (accuracy: 11.1m) -[2026-02-20T17:23:13.109802] LOG: [INIT] GPS service started, status: GpsStatus.locked -[2026-02-20T17:23:13.109803] LOG: [AUDIO] Initializing audio service -[2026-02-20T17:23:13.109804] LOG: [AUDIO] Opening Hive box "audio_preferences"... -[2026-02-20T17:23:13.110840] LOG: [AUDIO] Hive box "audio_preferences" opened successfully -[2026-02-20T17:23:13.110849] LOG: [AUDIO] No saved preference, using default: false -[2026-02-20T17:23:13.110983] LOG: [AUDIO] Audio session configured for notification mixing -[2026-02-20T17:23:13.125784] LOG: [MAP] Initial zoom to GPS position (with panel offset) -[2026-02-20T17:23:13.222236] LOG: [AUDIO] Audio service initialized, enabled=false -[2026-02-20T17:23:13.222294] LOG: [INIT] AppStateProvider initialization complete -[2026-02-20T17:23:13.222299] LOG: [INIT] Final init state: gpsStatus=GpsStatus.locked, inZone=null, isCheckingZone=true, hasPosition=true, offlineMode=false -[2026-02-20T17:23:14.020661] LOG: [API] POST /wardrive-api.php/status -[2026-02-20T17:23:14.020686] LOG: [API] Request: {"lat":47.3378661,"lng":-122.2247461,"accuracy_m":11.083000183105469,"ver":"APP-1771555184","timestamp":1771636993} -[2026-02-20T17:23:14.020692] LOG: [API] Response (200) in 0.91s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":11,"slots_max":15}} -[2026-02-20T17:23:14.020697] LOG: [GEOFENCE] API response received: valid -[2026-02-20T17:23:14.020703] LOG: [GEOFENCE] In zone: Seattle, US (SEA) -[2026-02-20T17:23:14.020705] LOG: [MAP] Fetching repeaters for zone: SEA -[2026-02-20T17:23:14.497259] LOG: [API] GET /get_repeaters.php -[2026-02-20T17:23:14.497296] LOG: [API] Request: none -[2026-02-20T17:23:14.497301] LOG: [API] Response (200) in 0.47s: 667 repeaters -[2026-02-20T17:23:14.497322] LOG: [MAP] Loaded 667 repeaters for zone SEA -[2026-02-20T17:23:14.497330] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA -[2026-02-20T17:23:25.652350] LOG: [APP] App resumed from background -[2026-02-20T17:23:26.427805] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:23:26.430129] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:23:28.176017] LOG: [BLE] Cached device info: MeshCore-Cozmo (F3:16:AF:D8:2B:1E) -[2026-02-20T17:23:28.176612] LOG: [APP] Creating new MeshCoreConnection -[2026-02-20T17:23:28.176880] LOG: [CONN] Step: ConnectionStep.bleConnecting -[2026-02-20T17:23:28.176891] LOG: [BLE] Connection attempt 1/3 to F3:16:AF:D8:2B:1E -[2026-02-20T17:23:28.176915] LOG: [BLE] Device reference created -[2026-02-20T17:23:28.176918] LOG: [BLE] Connecting to GATT... -[2026-02-20T17:23:28.435386] LOG: [BLE] GATT connected -[2026-02-20T17:23:28.847069] LOG: [BLE] MTU negotiated: 247 bytes -[2026-02-20T17:23:28.947639] LOG: [BLE] Discovering services... -[2026-02-20T17:23:29.265835] LOG: [BLE] Found 3 services -[2026-02-20T17:23:29.266082] LOG: [BLE] Found MeshCore service -[2026-02-20T17:23:29.266144] LOG: [BLE] Found TX characteristic -[2026-02-20T17:23:29.266198] LOG: [BLE] Found RX characteristic -[2026-02-20T17:23:29.266212] LOG: [BLE] Enabling notifications... -[2026-02-20T17:23:29.356416] LOG: [BLE] Notifications enabled -[2026-02-20T17:23:29.356535] LOG: [BLE] Device name: MeshCore-Cozmo (from scan: true, platformName: ) -[2026-02-20T17:23:29.356555] LOG: [BLE] Connection complete -[2026-02-20T17:23:29.356579] LOG: [CONN] Step: ConnectionStep.protocolHandshake -[2026-02-20T17:23:29.857651] LOG: [CONN] Step: ConnectionStep.deviceQuery -[2026-02-20T17:23:29.924351] LOG: [CONN] Frame received (80 bytes): 0d 08 af 28 00 00 00 00 32 39 2d 4a 61 6e 2d 32 30 32 36 00 48 65 6c 74 65 63 20 54 31 31 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 31 2e 31 32 2e 30 2d 65 37 33 38 61 37 34 00 00 00 00 00 -[2026-02-20T17:23:29.924426] LOG: [CONN] Response code: 0x0d (13) -[2026-02-20T17:23:29.924431] LOG: [CONN] Firmware version: 8 -[2026-02-20T17:23:29.924440] LOG: [CONN] Build date: 29-Jan-2026 -[2026-02-20T17:23:29.924445] LOG: [CONN] Manufacturer model: Heltec T114v1.12.0-e738a74 -[2026-02-20T17:23:29.986292] LOG: [CONN] Frame received (63 bytes): 05 01 16 16 f9 92 6e f7 f7 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f a5 eb ab b8 d2 02 0f 1a b9 f8 00 00 00 01 bd e4 0d 00 24 f4 00 00 07 05 43 6f 7a 6d 6f -[2026-02-20T17:23:29.986368] LOG: [CONN] Response code: 0x05 (5) -[2026-02-20T17:23:29.986388] LOG: [CONN] SelfInfo received: name="Cozmo", publicKey=F9926EF7F78C5689... -[2026-02-20T17:23:29.986441] LOG: [CONN] Public key acquired: F9926EF7F78C5689... -[2026-02-20T17:23:29.986453] LOG: [CONN] Step: ConnectionStep.powerConfiguration -[2026-02-20T17:23:29.986480] LOG: [CONN] Device identified: Heltec T114 (reports 0.3W / 22dBm) -[2026-02-20T17:23:29.986488] LOG: [CONN] Step: ConnectionStep.timeSync -[2026-02-20T17:23:30.043607] LOG: [CONN] Step: ConnectionStep.slotAcquisition -[2026-02-20T17:23:30.043653] LOG: [CONN] Requesting API session via geo-auth -[2026-02-20T17:23:30.043768] LOG: [APP] Stage 1: Attempting auth with public_key: F9926EF7F78C5689... -[2026-02-20T17:23:30.045077] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:23:30.045101] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:23:30.045105] LOG: [CONN] Received OK response -[2026-02-20T17:23:30.720589] LOG: [API] POST /wardrive-api.php/auth -[2026-02-20T17:23:30.720663] LOG: [API] Request: {"reason":"connect","who":"Cozmo","ver":"APP-1771555184","power":"0.3w","iata":"SEA","model":"Heltec T114","coords":{"lat":47.3378661,"lng":-122.2247461,"accuracy_m":11.083000183105469,"timestamp":1771637010}} -[2026-02-20T17:23:30.720688] LOG: [API] Response (200) in 0.68s: {"success":true,"tx_allowed":true,"rx_allowed":true,"zone":{"name":"Seattle, US","code":"SEA"},"expires_at":1771637310,"type":"API","debug_mode":0,"enforce_hybrid":false,"min_mode_interval":15,"channels":["public","bot","bot-tacoma","olybot","bot-islands","sipesbot"]} -[2026-02-20T17:23:30.721614] LOG: [API] Regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] -[2026-02-20T17:23:30.721653] LOG: [APP] Stage 1 succeeded: authenticated via public_key -[2026-02-20T17:23:30.721668] LOG: [APP] Auth type: API -[2026-02-20T17:23:30.721914] LOG: [CONN] API session acquired successfully (session_id: SEA-20260220-0034) -[2026-02-20T17:23:30.721934] LOG: [CONN] Step: ConnectionStep.channelSetup -[2026-02-20T17:23:30.721947] LOG: [CONN] Creating #wardriving channel -[2026-02-20T17:23:30.721964] LOG: [CHANNEL] Looking up channel: #wardriving -[2026-02-20T17:23:30.721974] LOG: [CONN] getChannel(0) - sending request -[2026-02-20T17:23:30.722006] LOG: [CONN] getChannel bytes: 0x1f 0x00 -[2026-02-20T17:23:30.768441] LOG: [CONN] Frame received (50 bytes): 12 00 50 75 62 6c 69 63 00 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 8b 33 87 e9 c5 cd ea 6a c9 e5 ed ba a1 15 cd 72 -[2026-02-20T17:23:30.768493] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:30.768551] LOG: [CONN] getChannel(1) - sending request -[2026-02-20T17:23:30.768563] LOG: [CONN] getChannel bytes: 0x1f 0x01 -[2026-02-20T17:23:30.827764] LOG: [CONN] Frame received (50 bytes): 12 01 23 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 62 e8 c7 49 22 e1 e3 9e 52 e2 2d 14 7c 9a c0 2f -[2026-02-20T17:23:30.827891] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:30.827929] LOG: [CONN] getChannel(2) - sending request -[2026-02-20T17:23:30.827948] LOG: [CONN] getChannel bytes: 0x1f 0x02 -[2026-02-20T17:23:30.886803] LOG: [CONN] Frame received (50 bytes): 12 02 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:30.886917] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:30.886952] LOG: [CHANNEL] Found empty slot at index 2 -[2026-02-20T17:23:30.886964] LOG: [CONN] getChannel(3) - sending request -[2026-02-20T17:23:30.886985] LOG: [CONN] getChannel bytes: 0x1f 0x03 -[2026-02-20T17:23:30.943951] LOG: [CONN] Frame received (50 bytes): 12 03 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:30.943995] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:30.944005] LOG: [CONN] getChannel(4) - sending request -[2026-02-20T17:23:30.944011] LOG: [CONN] getChannel bytes: 0x1f 0x04 -[2026-02-20T17:23:31.005283] LOG: [CONN] Frame received (50 bytes): 12 04 23 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 83 c8 b0 19 97 65 42 65 93 8d a8 76 5c bc 7d b9 -[2026-02-20T17:23:31.005393] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.005430] LOG: [CONN] getChannel(5) - sending request -[2026-02-20T17:23:31.005449] LOG: [CONN] getChannel bytes: 0x1f 0x05 -[2026-02-20T17:23:31.071519] LOG: [CONN] Frame received (50 bytes): 12 05 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.071653] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.071688] LOG: [CONN] getChannel(6) - sending request -[2026-02-20T17:23:31.071710] LOG: [CONN] getChannel bytes: 0x1f 0x06 -[2026-02-20T17:23:31.127745] LOG: [CONN] Frame received (50 bytes): 12 06 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.127881] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.127909] LOG: [CONN] getChannel(7) - sending request -[2026-02-20T17:23:31.127934] LOG: [CONN] getChannel bytes: 0x1f 0x07 -[2026-02-20T17:23:31.185489] LOG: [CONN] Frame received (50 bytes): 12 07 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.185590] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.185611] LOG: [CONN] getChannel(8) - sending request -[2026-02-20T17:23:31.185631] LOG: [CONN] getChannel bytes: 0x1f 0x08 -[2026-02-20T17:23:31.246401] LOG: [CONN] Frame received (50 bytes): 12 08 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.246666] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.247304] LOG: [CONN] getChannel(9) - sending request -[2026-02-20T17:23:31.247327] LOG: [CONN] getChannel bytes: 0x1f 0x09 -[2026-02-20T17:23:31.306890] LOG: [CONN] Frame received (50 bytes): 12 09 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.306943] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.306982] LOG: [CONN] getChannel(10) - sending request -[2026-02-20T17:23:31.307002] LOG: [CONN] getChannel bytes: 0x1f 0x0a -[2026-02-20T17:23:31.368449] LOG: [CONN] Frame received (50 bytes): 12 0a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.368568] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.368596] LOG: [CONN] getChannel(11) - sending request -[2026-02-20T17:23:31.368622] LOG: [CONN] getChannel bytes: 0x1f 0x0b -[2026-02-20T17:23:31.427308] LOG: [CONN] Frame received (50 bytes): 12 0b 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.427430] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.427465] LOG: [CONN] getChannel(12) - sending request -[2026-02-20T17:23:31.427485] LOG: [CONN] getChannel bytes: 0x1f 0x0c -[2026-02-20T17:23:31.484590] LOG: [CONN] Frame received (50 bytes): 12 0c 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.484648] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.484662] LOG: [CONN] getChannel(13) - sending request -[2026-02-20T17:23:31.484674] LOG: [CONN] getChannel bytes: 0x1f 0x0d -[2026-02-20T17:23:31.546211] LOG: [CONN] Frame received (50 bytes): 12 0d 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.546348] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.546412] LOG: [CONN] getChannel(14) - sending request -[2026-02-20T17:23:31.546432] LOG: [CONN] getChannel bytes: 0x1f 0x0e -[2026-02-20T17:23:31.606501] LOG: [CONN] Frame received (50 bytes): 12 0e 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.606720] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.606755] LOG: [CONN] getChannel(15) - sending request -[2026-02-20T17:23:31.606774] LOG: [CONN] getChannel bytes: 0x1f 0x0f -[2026-02-20T17:23:31.680142] LOG: [CONN] Frame received (50 bytes): 12 0f 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.680185] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.680193] LOG: [CONN] getChannel(16) - sending request -[2026-02-20T17:23:31.680200] LOG: [CONN] getChannel bytes: 0x1f 0x10 -[2026-02-20T17:23:31.725795] LOG: [CONN] Frame received (50 bytes): 12 10 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.725933] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.725968] LOG: [CONN] getChannel(17) - sending request -[2026-02-20T17:23:31.725989] LOG: [CONN] getChannel bytes: 0x1f 0x11 -[2026-02-20T17:23:31.786363] LOG: [CONN] Frame received (50 bytes): 12 11 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.786485] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.786556] LOG: [CONN] getChannel(18) - sending request -[2026-02-20T17:23:31.786579] LOG: [CONN] getChannel bytes: 0x1f 0x12 -[2026-02-20T17:23:31.845947] LOG: [CONN] Frame received (50 bytes): 12 12 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.846066] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.846099] LOG: [CONN] getChannel(19) - sending request -[2026-02-20T17:23:31.846126] LOG: [CONN] getChannel bytes: 0x1f 0x13 -[2026-02-20T17:23:31.906700] LOG: [CONN] Frame received (50 bytes): 12 13 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.906831] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.906866] LOG: [CONN] getChannel(20) - sending request -[2026-02-20T17:23:31.906886] LOG: [CONN] getChannel bytes: 0x1f 0x14 -[2026-02-20T17:23:31.967906] LOG: [CONN] Frame received (50 bytes): 12 14 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:31.968031] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:31.968098] LOG: [CONN] getChannel(21) - sending request -[2026-02-20T17:23:31.968121] LOG: [CONN] getChannel bytes: 0x1f 0x15 -[2026-02-20T17:23:32.028499] LOG: [CONN] Frame received (50 bytes): 12 15 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.028615] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.028644] LOG: [CONN] getChannel(22) - sending request -[2026-02-20T17:23:32.028678] LOG: [CONN] getChannel bytes: 0x1f 0x16 -[2026-02-20T17:23:32.087437] LOG: [CONN] Frame received (50 bytes): 12 16 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.087548] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.087581] LOG: [CONN] getChannel(23) - sending request -[2026-02-20T17:23:32.087601] LOG: [CONN] getChannel bytes: 0x1f 0x17 -[2026-02-20T17:23:32.145852] LOG: [CONN] Frame received (50 bytes): 12 17 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.145967] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.146] LOG: [CONN] getChannel(24) - sending request -[2026-02-20T17:23:32.146020] LOG: [CONN] getChannel bytes: 0x1f 0x18 -[2026-02-20T17:23:32.205869] LOG: [CONN] Frame received (50 bytes): 12 18 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.206025] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.206055] LOG: [CONN] getChannel(25) - sending request -[2026-02-20T17:23:32.206081] LOG: [CONN] getChannel bytes: 0x1f 0x19 -[2026-02-20T17:23:32.268053] LOG: [CONN] Frame received (50 bytes): 12 19 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.268196] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.268234] LOG: [CONN] getChannel(26) - sending request -[2026-02-20T17:23:32.268254] LOG: [CONN] getChannel bytes: 0x1f 0x1a -[2026-02-20T17:23:32.328078] LOG: [CONN] Frame received (50 bytes): 12 1a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.328197] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.328305] LOG: [CONN] getChannel(27) - sending request -[2026-02-20T17:23:32.328330] LOG: [CONN] getChannel bytes: 0x1f 0x1b -[2026-02-20T17:23:32.387626] LOG: [CONN] Frame received (33 bytes): 88 03 ca 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d -[2026-02-20T17:23:32.387745] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:32.416951] LOG: [CONN] Frame received (50 bytes): 12 1b 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.417052] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.417088] LOG: [CONN] getChannel(28) - sending request -[2026-02-20T17:23:32.417110] LOG: [CONN] getChannel bytes: 0x1f 0x1c -[2026-02-20T17:23:32.477648] LOG: [CONN] Frame received (50 bytes): 12 1c 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.477760] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.477793] LOG: [CONN] getChannel(29) - sending request -[2026-02-20T17:23:32.477813] LOG: [CONN] getChannel bytes: 0x1f 0x1d -[2026-02-20T17:23:32.537858] LOG: [CONN] Frame received (50 bytes): 12 1d 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.537990] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.538024] LOG: [CONN] getChannel(30) - sending request -[2026-02-20T17:23:32.538052] LOG: [CONN] getChannel bytes: 0x1f 0x1e -[2026-02-20T17:23:32.627697] LOG: [CONN] Frame received (50 bytes): 12 1e 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.627830] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.627864] LOG: [CONN] getChannel(31) - sending request -[2026-02-20T17:23:32.627884] LOG: [CONN] getChannel bytes: 0x1f 0x1f -[2026-02-20T17:23:32.685223] LOG: [CONN] Frame received (50 bytes): 12 1f 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.685310] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.685337] LOG: [CONN] getChannel(32) - sending request -[2026-02-20T17:23:32.685353] LOG: [CONN] getChannel bytes: 0x1f 0x20 -[2026-02-20T17:23:32.748958] LOG: [CONN] Frame received (50 bytes): 12 20 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.749091] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.749357] LOG: [CONN] getChannel(33) - sending request -[2026-02-20T17:23:32.749410] LOG: [CONN] getChannel bytes: 0x1f 0x21 -[2026-02-20T17:23:32.805291] LOG: [CONN] Frame received (50 bytes): 12 21 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.805380] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.805404] LOG: [CONN] getChannel(34) - sending request -[2026-02-20T17:23:32.805419] LOG: [CONN] getChannel bytes: 0x1f 0x22 -[2026-02-20T17:23:32.865906] LOG: [CONN] Frame received (50 bytes): 12 22 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.865991] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.866012] LOG: [CONN] getChannel(35) - sending request -[2026-02-20T17:23:32.866023] LOG: [CONN] getChannel bytes: 0x1f 0x23 -[2026-02-20T17:23:32.926216] LOG: [CONN] Frame received (50 bytes): 12 23 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.926347] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.926378] LOG: [CONN] getChannel(36) - sending request -[2026-02-20T17:23:32.926412] LOG: [CONN] getChannel bytes: 0x1f 0x24 -[2026-02-20T17:23:32.987593] LOG: [CONN] Frame received (50 bytes): 12 24 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:32.987722] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:32.987760] LOG: [CONN] getChannel(37) - sending request -[2026-02-20T17:23:32.987780] LOG: [CONN] getChannel bytes: 0x1f 0x25 -[2026-02-20T17:23:33.044708] LOG: [CONN] Frame received (50 bytes): 12 25 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:33.044807] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:33.044830] LOG: [CONN] getChannel(38) - sending request -[2026-02-20T17:23:33.044842] LOG: [CONN] getChannel bytes: 0x1f 0x26 -[2026-02-20T17:23:33.107683] LOG: [CONN] Frame received (50 bytes): 12 26 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:33.107804] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:33.107835] LOG: [CONN] getChannel(39) - sending request -[2026-02-20T17:23:33.107860] LOG: [CONN] getChannel bytes: 0x1f 0x27 -[2026-02-20T17:23:33.167946] LOG: [CONN] Frame received (50 bytes): 12 27 00 15 0b dd 48 c7 7e 75 20 20 20 53 7e cc ca 7f 39 d2 ce 8b c9 63 aa 2b fc 7d 79 f4 6e c5 1d 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:23:33.168063] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:23:33.168098] LOG: [CONN] getChannel(40) - sending request -[2026-02-20T17:23:33.168119] LOG: [CONN] getChannel bytes: 0x1f 0x28 -[2026-02-20T17:23:33.226057] LOG: [CONN] Frame received (2 bytes): 01 02 -[2026-02-20T17:23:33.226163] LOG: [CONN] Response code: 0x01 (1) -[2026-02-20T17:23:33.226183] LOG: [CONN] Received ERR response (error code: 2) -[2026-02-20T17:23:33.226258] LOG: [CHANNEL] Scan stopped at channel 40 (error: Exception: Command error (code 2)) -[2026-02-20T17:23:33.226276] LOG: [CHANNEL] #wardriving not found in 40 channels, creating at index 2 -[2026-02-20T17:23:33.226291] LOG: [CRYPTO] Deriving channel key for: #wardriving -[2026-02-20T17:23:33.226453] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.284849] LOG: [CHANNEL] Channel #wardriving created successfully at index 2 -[2026-02-20T17:23:33.284963] LOG: [CONN] Channel ready: #wardriving (CH:2) -[2026-02-20T17:23:33.284982] LOG: [CONN] Step: ConnectionStep.gpsInit -[2026-02-20T17:23:33.284998] LOG: [CONN] Step: ConnectionStep.connected -[2026-02-20T17:23:33.285012] LOG: [CONN] Connection workflow complete -[2026-02-20T17:23:33.285131] LOG: [APP] Device public key stored: F9926EF7F78C5689... -[2026-02-20T17:23:33.285148] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:33.285183] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:33.287019] LOG: [APP] Saved last connected device: Cozmo -[2026-02-20T17:23:33.485964] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:23:33.486176] LOG: [CONN] Started battery polling (30s interval) -[2026-02-20T17:23:33.486194] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:33.486229] LOG: [CONN] Started noise floor polling (5s interval) -[2026-02-20T17:23:33.486343] LOG: [MODEL] Device recognized: Heltec T114 - reporting 0.3W in API calls -[2026-02-20T17:23:33.486357] LOG: [APP] Creating unified RX handler -[2026-02-20T17:23:33.486500] LOG: [APP] TxTracker.carpeaterPrefix set to CC -[2026-02-20T17:23:33.486598] LOG: [APP] TxTracker.onCarpeaterDrop callback SET -[2026-02-20T17:23:33.486706] LOG: [APP] PacketValidator configured with 1 channels: Public -[2026-02-20T17:23:33.486725] LOG: [UNIFIED RX] Starting unified RX listening -[2026-02-20T17:23:33.486734] LOG: [UNIFIED RX] ✅ Unified listening started successfully -[2026-02-20T17:23:33.486746] LOG: [APP] Unified RX handler created and listening -[2026-02-20T17:23:33.486894] LOG: [CHANNEL] Setting regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] -[2026-02-20T17:23:33.486920] LOG: [CRYPTO] Deriving channel key for: #wardriving -[2026-02-20T17:23:33.486976] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487] LOG: [CHANNEL] Added: #wardriving -> hash=129 -[2026-02-20T17:23:33.487013] LOG: [CRYPTO] Deriving channel key for: #bot -[2026-02-20T17:23:33.487038] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487063] LOG: [CHANNEL] Added: #bot -> hash=202 -[2026-02-20T17:23:33.487074] LOG: [CRYPTO] Deriving channel key for: #bot-tacoma -[2026-02-20T17:23:33.487110] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487128] LOG: [CHANNEL] Added: #bot-tacoma -> hash=5 -[2026-02-20T17:23:33.487143] LOG: [CRYPTO] Deriving channel key for: #olybot -[2026-02-20T17:23:33.487162] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487185] LOG: [CHANNEL] Added: #olybot -> hash=221 -[2026-02-20T17:23:33.487195] LOG: [CRYPTO] Deriving channel key for: #bot-islands -[2026-02-20T17:23:33.487239] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487261] LOG: [CHANNEL] Added: #bot-islands -> hash=183 -[2026-02-20T17:23:33.487271] LOG: [CRYPTO] Deriving channel key for: #sipesbot -[2026-02-20T17:23:33.487295] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:23:33.487315] LOG: [CHANNEL] Added: #sipesbot -> hash=97 -[2026-02-20T17:23:33.487326] LOG: [CHANNEL] Total channels: 7 -[2026-02-20T17:23:33.487361] LOG: [APP] Regional channels configured: [#bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot] -[2026-02-20T17:23:33.487390] LOG: [UNIFIED RX] Validator updated with new channel configuration -[2026-02-20T17:23:33.487408] LOG: [APP] PacketValidator updated with 7 channels: Public, #wardriving, #bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot -[2026-02-20T17:23:33.487428] LOG: [CONN] No regional scope — using unscoped flood -[2026-02-20T17:23:33.487446] LOG: [HIVE] Opening box "remembered_device"... -[2026-02-20T17:23:33.487799] LOG: [HIVE] Box "remembered_device" opened successfully -[2026-02-20T17:23:33.489907] LOG: [APP] Saved remembered device: MeshCore-Cozmo -[2026-02-20T17:23:33.490084] LOG: [APP] Display name set: "Cozmo" -[2026-02-20T17:23:33.490118] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:23:33.490162] LOG: [APP] Restored antenna preference for "Cozmo": external -[2026-02-20T17:23:33.490175] LOG: [CONN] Connected with full access (TX + RX allowed) -[2026-02-20T17:23:33.490201] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:23:33.490902] LOG: [APP] Saved preferences -[2026-02-20T17:23:34.339478] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:23:34.339633] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:23:34.339646] LOG: [CONN] Received OK response -[2026-02-20T17:23:34.365774] LOG: [CONN] Frame received (11 bytes): 0c f7 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:23:34.365889] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:23:34.365908] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:23:34.365931] LOG: [CONN] Battery updated: 4087mV (91%) -[2026-02-20T17:23:34.366472] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ca 03 04 00 00 00 cd 22 00 00 -[2026-02-20T17:23:34.366500] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:34.366586] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:23:37.803214] LOG: [CONN] Frame received (143 bytes): 88 2f b8 15 07 51 01 7a 1e e0 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 07 a0 bd -[2026-02-20T17:23:37.803251] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:37.803292] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:37.803348] LOG: [RX PARSE] RAW Packet (140 bytes): 15 07 51 01 7A 1E E0 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 07 A0 BD -[2026-02-20T17:23:37.803363] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:37.803369] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T17:23:37.803387] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x51, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=131 bytes -[2026-02-20T17:23:37.803396] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T17:23:38.314167] LOG: [CONN] Frame received (143 bytes): 88 31 b9 15 07 51 01 7a 1e e0 7e cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 07 a0 bd -[2026-02-20T17:23:38.314334] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:38.314367] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:38.314500] LOG: [RX PARSE] RAW Packet (140 bytes): 15 07 51 01 7A 1E E0 7E CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 07 A0 BD -[2026-02-20T17:23:38.314597] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:38.314610] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T17:23:38.314641] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x51, lastHop=0xcc, SNR=12.25, RSSI=-71, payload=131 bytes -[2026-02-20T17:23:38.314660] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T17:23:38.486833] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:38.656163] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b9 31 04 00 00 00 ce 22 00 00 -[2026-02-20T17:23:38.656313] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:38.656335] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:23:41.427685] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:23:41.427767] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:23:43.486866] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:43.695488] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b9 31 04 00 00 00 ce 22 00 00 -[2026-02-20T17:23:43.695608] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:43.695624] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:23:48.486920] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:48.586967] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 31 04 00 00 00 ce 22 00 00 -[2026-02-20T17:23:48.587109] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:48.587130] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:23:50.672853] LOG: [CONN] Frame received (146 bytes): 88 31 b8 15 0d 51 01 7a 1e e0 7e c5 75 20 20 53 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 -[2026-02-20T17:23:50.672950] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:50.672973] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:50.673029] LOG: [RX PARSE] RAW Packet (143 bytes): 15 0D 51 01 7A 1E E0 7E C5 75 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 -[2026-02-20T17:23:50.673041] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:50.673050] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T17:23:50.673063] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x51, lastHop=0xdd, SNR=12.25, RSSI=-72, payload=128 bytes -[2026-02-20T17:23:50.673072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T17:23:51.773094] LOG: [SESSION] Checking session validity via heartbeat... -[2026-02-20T17:23:51.933636] LOG: [CONN] Frame received (147 bytes): 88 2f b9 15 0e 51 01 7a 1e e0 7e c5 75 20 20 53 7e dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 67 04 cc a8 -[2026-02-20T17:23:51.933753] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:51.933780] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:51.933876] LOG: [RX PARSE] RAW Packet (144 bytes): 15 0E 51 01 7A 1E E0 7E C5 75 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 67 04 CC A8 -[2026-02-20T17:23:51.933897] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:51.933907] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T17:23:51.933930] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x51, lastHop=0xcc, SNR=11.75, RSSI=-71, payload=128 bytes -[2026-02-20T17:23:51.933941] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T17:23:52.114568] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T17:23:52.114682] LOG: [API] Request: {"heartbeat":true,"has_coords":true} -[2026-02-20T17:23:52.114697] LOG: [API] Response (200) in 0.34s: {"success":true,"expires_at":1771637332} -[2026-02-20T17:23:52.114736] LOG: [SESSION] Session is valid (expires_at: 1771637332) -[2026-02-20T17:23:52.114802] LOG: [PING] Starting auto mode: active -[2026-02-20T17:23:52.114815] LOG: [PING] Auto-ping interval set to 30000ms -[2026-02-20T17:23:52.114832] LOG: [PING] Using interval from preferences: 30s (30000ms) -[2026-02-20T17:23:52.114846] LOG: [AUTO] enableAutoPing called (passiveMode=false, hybridMode=false) -[2026-02-20T17:23:52.114857] LOG: [AUTO] Acquiring wake lock for auto mode -[2026-02-20T17:23:52.116338] LOG: [WAKELOCK] Screen wake lock enabled -[2026-02-20T17:23:52.116354] LOG: [ACTIVE MODE] Sending initial auto ping -[2026-02-20T17:23:52.116365] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T17:23:52.116394] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T17:23:52.116442] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.33787, -122.22475 [0.3w]" -[2026-02-20T17:23:52.116460] LOG: [TX LOG] Starting echo tracking -[2026-02-20T17:23:52.116470] LOG: [TX LOG] Payload: "@[MapperBot] 47.33787, -122.22475 [0.3w]" -[2026-02-20T17:23:52.116483] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T17:23:52.116502] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T17:23:52.116514] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T17:23:52.116524] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T17:23:52.116547] LOG: [CONN] Sending ping: @[MapperBot] 47.33787, -122.22475 [0.3w] -[2026-02-20T17:23:52.116615] LOG: [RX LOG] Starting passive RX wardriving -[2026-02-20T17:23:52.116874] LOG: [GRAPH] Started active noise floor session -[2026-02-20T17:23:52.116889] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T17:23:52.116908] LOG: [HEARTBEAT] Heartbeat mode enabled -[2026-02-20T17:23:52.116919] LOG: [HEARTBEAT] Enabled for active Mode -[2026-02-20T17:23:52.116929] LOG: [BACKGROUND] Starting background service (mode: Active Mode) -[2026-02-20T17:23:52.136471] LOG: [BACKGROUND] Background service started -[2026-02-20T17:23:52.278962] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:23:52.279072] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:23:52.279083] LOG: [CONN] Received OK response -[2026-02-20T17:23:53.487070] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:53.537486] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 2f 04 00 00 00 cf 22 00 00 -[2026-02-20T17:23:53.537606] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:53.537630] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:23:53.810729] LOG: [CONN] Frame received (73 bytes): 88 33 ba 15 01 cc 81 cf 4f 3c 5b a7 8b 88 d0 50 1f a7 55 76 a1 d2 d1 86 94 ca 29 8b 67 ce 86 ed 39 61 d7 87 88 d5 7a 58 80 4b 4b 25 30 80 59 13 5a a4 af 71 a7 f0 45 48 e2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T17:23:53.810854] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:53.810890] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:53.810962] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 CF 4F 3C 5B A7 8B 88 D0 50 1F A7 55 76 A1 D2 D1 86 94 CA 29 8B 67 CE 86 ED 39 61 D7 87 88 D5 7A 58 80 4B 4B 25 30 80 59 13 5A A4 AF 71 A7 F0 45 48 E2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T17:23:53.810978] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:53.810994] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T17:23:53.811021] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-70, payload=67 bytes -[2026-02-20T17:23:53.811040] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T17:23:53.811052] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T17:23:53.811064] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-70 -[2026-02-20T17:23:53.811087] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T17:23:53.811098] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T17:23:53.811111] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T17:23:53.811126] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T17:23:53.811136] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T17:23:55.284149] LOG: [PING] Ping sent successfully -[2026-02-20T17:23:56.427862] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:23:56.427960] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:23:57.117169] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T17:23:58.486674] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:23:58.546421] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 33 04 00 00 00 cf 22 00 00 -[2026-02-20T17:23:58.546600] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:23:58.546620] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:23:59.344641] LOG: [CONN] Frame received (146 bytes): 88 2f b8 15 11 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 53 7e dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 -[2026-02-20T17:23:59.344761] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:23:59.344787] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:23:59.344883] LOG: [RX PARSE] RAW Packet (143 bytes): 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:23:59.344903] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:23:59.344911] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T17:23:59.344932] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0x51, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=124 bytes -[2026-02-20T17:23:59.344943] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T17:23:59.344955] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T17:23:59.344964] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T17:23:59.345050] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T17:23:59.345063] LOG: [RX FILTER] Raw packet (143 bytes): 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:23:59.345084] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 11.75 -[2026-02-20T17:23:59.345097] LOG: [RX FILTER] ✓ RSSI OK (-72 < -30) -[2026-02-20T17:23:59.345105] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T17:23:59.345118] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T17:23:59.345127] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T17:23:59.345136] LOG: [RX FILTER] Encrypted message: 121 bytes -[2026-02-20T17:23:59.345149] LOG: [CRYPTO] Decrypting message (121 bytes) -[2026-02-20T17:23:59.345393] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T17:23:59.345449] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T17:23:59.345614] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T17:23:59.345755] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T17:23:59.345764] LOG: [RX LOG] Dropped packet hex: 15 11 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:24:00.284691] LOG: [PING] RX listening window ended -[2026-02-20T17:24:00.284803] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T17:24:00.284829] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T17:24:00.284923] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T17:24:00.284933] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T17:24:00.284942] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T17:24:00.284964] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T17:24:00.284975] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T17:24:00.285320] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T17:24:01.743334] LOG: [CONN] Frame received (147 bytes): 88 30 ba 15 12 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 53 7e dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 79 11 34 -[2026-02-20T17:24:01.743367] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:01.743391] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:01.743447] LOG: [RX PARSE] RAW Packet (144 bytes): 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:24:01.743460] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:24:01.743467] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T17:24:01.743482] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x51, lastHop=0xcc, SNR=12.0, RSSI=-70, payload=124 bytes -[2026-02-20T17:24:01.743490] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T17:24:01.743494] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T17:24:01.743500] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T17:24:01.743552] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T17:24:01.743559] LOG: [RX FILTER] Raw packet (144 bytes): 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:24:01.743572] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.0 -[2026-02-20T17:24:01.743578] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) -[2026-02-20T17:24:01.743583] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T17:24:01.743590] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T17:24:01.743595] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T17:24:01.743600] LOG: [RX FILTER] Encrypted message: 121 bytes -[2026-02-20T17:24:01.743606] LOG: [CRYPTO] Decrypting message (121 bytes) -[2026-02-20T17:24:01.743717] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T17:24:01.743792] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T17:24:01.743898] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T17:24:01.743969] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T17:24:01.743974] LOG: [RX LOG] Dropped packet hex: 15 12 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 53 7E DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 79 11 34 -[2026-02-20T17:24:01.934116] LOG: [PING] Stopping auto mode: active -[2026-02-20T17:24:01.934242] LOG: [PING] disableAutoPing called -[2026-02-20T17:24:01.935601] LOG: [WAKELOCK] Screen wake lock disabled -[2026-02-20T17:24:01.935646] LOG: [PING] Auto-ping disabled -[2026-02-20T17:24:01.935662] LOG: [PING] Stopping TX echo tracking and RX window timer -[2026-02-20T17:24:01.935674] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T17:24:01.935683] LOG: [RX LOG] Stopping passive RX wardriving: trigger=user_stop -[2026-02-20T17:24:01.935698] LOG: [RX BATCH] Flushing all repeaters, trigger=user_stop, active_repeaters=0 -[2026-02-20T17:24:01.935707] LOG: [RX BATCH] No repeaters to flush -[2026-02-20T17:24:01.935718] LOG: [BACKGROUND] Stopping background service -[2026-02-20T17:24:01.935776] LOG: [BACKGROUND] Background service stopped -[2026-02-20T17:24:01.935848] LOG: [GRAPH] Ended session: 0:09, 2 samples, 1 markers -[2026-02-20T17:24:01.942189] LOG: [HEARTBEAT] Heartbeat mode disabled -[2026-02-20T17:24:01.942251] LOG: [ACTIVE MODE] Shared cooldown started (5s) - blocks TX Ping and TX modes -[2026-02-20T17:24:03.486952] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:24:03.487085] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:03.585481] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:24:03.585584] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:24:03.585604] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:24:03.585617] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T17:24:03.645696] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 30 04 00 00 00 d0 22 00 00 -[2026-02-20T17:24:03.645780] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:03.645793] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:24:05.286047] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T17:24:05.286370] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T17:24:05.286386] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T17:24:05.756095] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T17:24:05.756177] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T17:24:05.756200] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771637345} -[2026-02-20T17:24:05.756222] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T17:24:05.756769] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T17:24:05.756787] LOG: [APP] Upload success: +1 items (total: 1) -[2026-02-20T17:24:06.943286] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T17:24:08.487036] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:08.656245] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 30 04 00 00 00 d0 22 00 00 -[2026-02-20T17:24:08.656364] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:08.656392] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:24:08.720164] LOG: [CONN] Frame received (148 bytes): 88 2e b8 15 16 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 20 20 20 75 a5 e8 9b dd ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 -[2026-02-20T17:24:08.720235] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:08.720258] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:08.720307] LOG: [RX PARSE] RAW Packet (145 bytes): 15 16 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 20 20 20 75 A5 E8 9B DD CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 -[2026-02-20T17:24:08.720317] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:24:08.720327] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T17:24:08.720345] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x51, lastHop=0xdd, SNR=11.5, RSSI=-72, payload=121 bytes -[2026-02-20T17:24:08.720353] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T17:24:10.329734] LOG: [CONN] Frame received (149 bytes): 88 2f ba 15 17 51 01 7a 1e e0 7e c5 75 20 20 20 20 20 20 20 20 20 75 a5 e8 9b dd cc ca e3 49 d8 f7 65 f1 58 8a 18 21 27 58 46 00 48 a3 02 9d 0e 33 86 db 94 a6 c8 24 6f 86 cf 74 2b c8 d3 53 15 bd f2 92 6a f5 d3 92 c8 d9 a6 4b 8a 69 61 9d a5 9a 06 11 d5 fb 7b c2 2d 64 1d a1 6e 96 7c e2 fe 52 93 82 dd a8 f7 d9 0c 1a ec b8 0d 25 73 0a 8c 34 c9 25 a7 c2 41 2f b1 a1 a8 a4 30 40 1a 54 a1 51 b5 9e cb 66 13 1a e5 0b 13 0d 33 db 70 c0 6e 42 11 aa 4e 08 -[2026-02-20T17:24:10.329819] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:10.329838] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:10.329892] LOG: [RX PARSE] RAW Packet (146 bytes): 15 17 51 01 7A 1E E0 7E C5 75 20 20 20 20 20 20 20 20 20 75 A5 E8 9B DD CC CA E3 49 D8 F7 65 F1 58 8A 18 21 27 58 46 00 48 A3 02 9D 0E 33 86 DB 94 A6 C8 24 6F 86 CF 74 2B C8 D3 53 15 BD F2 92 6A F5 D3 92 C8 D9 A6 4B 8A 69 61 9D A5 9A 06 11 D5 FB 7B C2 2D 64 1D A1 6E 96 7C E2 FE 52 93 82 DD A8 F7 D9 0C 1A EC B8 0D 25 73 0A 8C 34 C9 25 A7 C2 41 2F B1 A1 A8 A4 30 40 1A 54 A1 51 B5 9E CB 66 13 1A E5 0B 13 0D 33 DB 70 C0 6E 42 11 AA 4E 08 -[2026-02-20T17:24:10.329904] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:24:10.329913] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T17:24:10.329924] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0x51, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=121 bytes -[2026-02-20T17:24:10.329933] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 -[2026-02-20T17:24:10.758035] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T17:24:11.428058] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:24:11.428171] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:24:13.486626] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:13.668239] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff ba 2f 04 00 00 00 d1 22 00 00 -[2026-02-20T17:24:13.668396] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:13.668423] LOG: [CONN] Noise floor updated: -117dBm -[2026-02-20T17:24:18.487340] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:18.676312] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2f 04 00 00 00 d1 22 00 00 -[2026-02-20T17:24:18.676418] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:18.676433] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:24:19.353041] LOG: [CONN] Frame received (33 bytes): 88 32 b8 21 0a 73 86 7e 75 20 20 20 53 7e dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 1c -[2026-02-20T17:24:19.353173] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:19.353212] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:19.353257] LOG: [RX PARSE] RAW Packet (30 bytes): 21 0A 73 86 7E 75 20 20 20 53 7E DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 1C -[2026-02-20T17:24:19.353271] LOG: [RX PARSE] Header: 0x21, Route type: 1 -[2026-02-20T17:24:19.353286] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T17:24:19.353317] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=10, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-72, payload=18 bytes -[2026-02-20T17:24:19.353335] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=10 -[2026-02-20T17:24:20.132913] LOG: [CONN] Frame received (34 bytes): 88 31 bb 21 0b 73 86 7e 75 20 20 20 53 7e dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 1c -[2026-02-20T17:24:20.133052] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:20.133090] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:20.133135] LOG: [RX PARSE] RAW Packet (31 bytes): 21 0B 73 86 7E 75 20 20 20 53 7E DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 1C -[2026-02-20T17:24:20.133148] LOG: [RX PARSE] Header: 0x21, Route type: 1 -[2026-02-20T17:24:20.133163] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T17:24:20.133185] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=11, firstHop=0x73, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=18 bytes -[2026-02-20T17:24:20.133198] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=11 -[2026-02-20T17:24:22.354205] LOG: [CONN] Frame received (40 bytes): 88 2f ba 21 12 73 86 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 7e dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 -[2026-02-20T17:24:22.354266] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:22.354310] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:22.354354] LOG: [RX PARSE] RAW Packet (37 bytes): 21 12 73 86 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 7E DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 -[2026-02-20T17:24:22.354373] LOG: [RX PARSE] Header: 0x21, Route type: 1 -[2026-02-20T17:24:22.354385] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T17:24:22.354413] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=18, firstHop=0x73, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=17 bytes -[2026-02-20T17:24:22.354427] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=18 -[2026-02-20T17:24:23.487194] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:23.596603] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2f 04 00 00 00 d1 22 00 00 -[2026-02-20T17:24:23.596720] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:23.596742] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:24:25.560985] LOG: [CONN] Frame received (45 bytes): 88 32 ba 01 17 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 38 7e cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 -[2026-02-20T17:24:25.561042] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:25.561054] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:25.561067] LOG: [RX PARSE] RAW Packet (42 bytes): 01 17 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 38 7E CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 -[2026-02-20T17:24:25.561071] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:25.561074] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T17:24:25.561083] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=23, firstHop=0x73, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=17 bytes -[2026-02-20T17:24:25.561086] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=23 -[2026-02-20T17:24:25.830973] LOG: [CONN] Frame received (48 bytes): 88 2f b9 01 1a 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 1e 8e 1f 9b dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 f6 -[2026-02-20T17:24:25.831124] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:25.831157] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:25.831208] LOG: [RX PARSE] RAW Packet (45 bytes): 01 1A 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 1E 8E 1F 9B DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 F6 -[2026-02-20T17:24:25.831228] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:25.831240] LOG: [RX PARSE] Path length offset: 1, Path length: 26 -[2026-02-20T17:24:25.831276] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=26, firstHop=0x73, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=17 bytes -[2026-02-20T17:24:25.831291] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=26 -[2026-02-20T17:24:26.427785] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:24:26.427909] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:24:27.725432] LOG: [CONN] Frame received (51 bytes): 88 34 b9 01 1e 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 -[2026-02-20T17:24:27.725611] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:27.725653] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:27.725706] LOG: [RX PARSE] RAW Packet (48 bytes): 01 1E 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 -[2026-02-20T17:24:27.725722] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:27.725738] LOG: [RX PARSE] Path length offset: 1, Path length: 30 -[2026-02-20T17:24:27.725773] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=30, firstHop=0x73, lastHop=0xcc, SNR=13.0, RSSI=-71, payload=16 bytes -[2026-02-20T17:24:27.725791] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=30 -[2026-02-20T17:24:28.083245] LOG: [CONN] Frame received (53 bytes): 88 2d b7 01 20 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e 9d 9b dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 86 -[2026-02-20T17:24:28.083373] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:28.083401] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:28.083462] LOG: [RX PARSE] RAW Packet (50 bytes): 01 20 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E 9D 9B DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 86 -[2026-02-20T17:24:28.083477] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:28.083494] LOG: [RX PARSE] Path length offset: 1, Path length: 32 -[2026-02-20T17:24:28.083523] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=32, firstHop=0x73, lastHop=0xdd, SNR=11.25, RSSI=-73, payload=16 bytes -[2026-02-20T17:24:28.083543] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=32 -[2026-02-20T17:24:28.486725] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:28.574735] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b7 2d 04 00 00 00 d2 22 00 00 -[2026-02-20T17:24:28.574781] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:28.574787] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:24:29.251527] LOG: [CONN] Frame received (51 bytes): 88 32 b8 01 26 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 75 2b 24 a5 9d dd 1e a8 69 18 73 3a 7e dd -[2026-02-20T17:24:29.251620] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:29.251634] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:29.251649] LOG: [RX PARSE] RAW Packet (48 bytes): 01 26 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 75 2B 24 A5 9D DD 1E A8 69 18 73 3A 7E DD -[2026-02-20T17:24:29.251655] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:29.251658] LOG: [RX PARSE] Path length offset: 1, Path length: 38 -[2026-02-20T17:24:29.251670] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=38, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-72, payload=8 bytes -[2026-02-20T17:24:29.251674] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=38 -[2026-02-20T17:24:29.761691] LOG: [CONN] Frame received (52 bytes): 88 33 ba 01 27 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 75 2b 24 a5 9d dd cc 1e a8 69 18 73 3a 7e dd -[2026-02-20T17:24:29.761763] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:29.761786] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:29.761812] LOG: [RX PARSE] RAW Packet (49 bytes): 01 27 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 75 2B 24 A5 9D DD CC 1E A8 69 18 73 3A 7E DD -[2026-02-20T17:24:29.761821] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:29.761826] LOG: [RX PARSE] Path length offset: 1, Path length: 39 -[2026-02-20T17:24:29.761837] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=39, firstHop=0x73, lastHop=0xcc, SNR=12.75, RSSI=-70, payload=8 bytes -[2026-02-20T17:24:29.761846] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=39 -[2026-02-20T17:24:33.091381] LOG: [CONN] Frame received (55 bytes): 88 2f b8 01 2d 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 f4 f1 ea 65 7d e8 9b dd 1e a8 69 18 73 -[2026-02-20T17:24:33.091405] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:33.091421] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:33.091439] LOG: [RX PARSE] RAW Packet (52 bytes): 01 2D 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 F4 F1 EA 65 7D E8 9B DD 1E A8 69 18 73 -[2026-02-20T17:24:33.091443] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:33.091448] LOG: [RX PARSE] Path length offset: 1, Path length: 45 -[2026-02-20T17:24:33.091463] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=45, firstHop=0x73, lastHop=0xdd, SNR=11.75, RSSI=-72, payload=5 bytes -[2026-02-20T17:24:33.091467] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=45 -[2026-02-20T17:24:33.359062] LOG: [CONN] Frame received (56 bytes): 88 30 b9 01 2e 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 f4 f1 ea 65 7d e8 9b dd cc 1e a8 69 18 73 -[2026-02-20T17:24:33.359156] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:33.359179] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:33.359231] LOG: [RX PARSE] RAW Packet (53 bytes): 01 2E 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 F4 F1 EA 65 7D E8 9B DD CC 1E A8 69 18 73 -[2026-02-20T17:24:33.359235] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:33.359243] LOG: [RX PARSE] Path length offset: 1, Path length: 46 -[2026-02-20T17:24:33.359255] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=46, firstHop=0x73, lastHop=0xcc, SNR=12.0, RSSI=-71, payload=5 bytes -[2026-02-20T17:24:33.359262] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=46 -[2026-02-20T17:24:33.486728] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:24:33.486841] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:33.554131] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:24:33.554159] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:24:33.554163] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:24:33.554166] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T17:24:33.614189] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff b9 30 04 00 00 00 d3 22 00 00 -[2026-02-20T17:24:33.614223] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:33.614230] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T17:24:38.487055] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:38.657190] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b9 30 04 00 00 00 d3 22 00 00 -[2026-02-20T17:24:38.657341] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:38.657384] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:24:40.082447] LOG: [CONN] Frame received (69 bytes): 88 32 b6 01 30 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e e0 7a 61 a4 c9 ca ab 99 2a 94 de a4 5d cd 6c 13 e8 32 dd 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 46 -[2026-02-20T17:24:40.082561] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:40.082606] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:40.082648] LOG: [RX PARSE] RAW Packet (66 bytes): 01 30 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E E0 7A 61 A4 C9 CA AB 99 2A 94 DE A4 5D CD 6C 13 E8 32 DD 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 46 -[2026-02-20T17:24:40.082658] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:40.082662] LOG: [RX PARSE] Path length offset: 1, Path length: 48 -[2026-02-20T17:24:40.082675] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=48, firstHop=0x73, lastHop=0xdd, SNR=12.5, RSSI=-74, payload=16 bytes -[2026-02-20T17:24:40.082682] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=48 -[2026-02-20T17:24:40.562890] LOG: [CONN] Frame received (70 bytes): 88 32 ba 01 31 73 84 7e 75 20 20 20 20 75 67 38 24 1c 5f e3 86 6b 22 6e 6b 2b 75 20 20 75 65 07 f4 7e e0 7a 61 a4 c9 ca ab 99 2a 94 de a4 5d cd 6c 13 e8 32 dd cc 1e a8 69 18 73 3a 7e dd 02 29 0f 8c ce 79 62 46 -[2026-02-20T17:24:40.563033] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:40.563061] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:40.563115] LOG: [RX PARSE] RAW Packet (67 bytes): 01 31 73 84 7E 75 20 20 20 20 75 67 38 24 1C 5F E3 86 6B 22 6E 6B 2B 75 20 20 75 65 07 F4 7E E0 7A 61 A4 C9 CA AB 99 2A 94 DE A4 5D CD 6C 13 E8 32 DD CC 1E A8 69 18 73 3A 7E DD 02 29 0F 8C CE 79 62 46 -[2026-02-20T17:24:40.563127] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T17:24:40.563140] LOG: [RX PARSE] Path length offset: 1, Path length: 49 -[2026-02-20T17:24:40.563160] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=49, firstHop=0x73, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=16 bytes -[2026-02-20T17:24:40.563173] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=49 -[2026-02-20T17:24:41.428065] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:24:41.428196] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:24:43.487099] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:43.604832] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 32 04 00 00 00 d4 22 00 00 -[2026-02-20T17:24:43.604911] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:43.604923] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:24:44.343077] LOG: [CONN] Frame received (44 bytes): 88 34 b5 05 03 24 7e dd bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b 7b 13 57 20 68 66 16 a9 33 -[2026-02-20T17:24:44.343196] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:44.343219] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:44.343264] LOG: [RX PARSE] RAW Packet (41 bytes): 05 03 24 7E DD BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B 7B 13 57 20 68 66 16 A9 33 -[2026-02-20T17:24:44.343278] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:44.343286] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T17:24:44.343308] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x24, lastHop=0xdd, SNR=13.0, RSSI=-75, payload=36 bytes -[2026-02-20T17:24:44.343319] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 -[2026-02-20T17:24:44.896398] LOG: [CONN] Frame received (44 bytes): 88 34 b9 05 03 24 7e cc bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b 7b 13 57 20 68 66 16 a9 33 -[2026-02-20T17:24:44.896560] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:44.896602] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:44.896650] LOG: [RX PARSE] RAW Packet (41 bytes): 05 03 24 7E CC BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B 7B 13 57 20 68 66 16 A9 33 -[2026-02-20T17:24:44.896665] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:44.896680] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T17:24:44.896708] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x24, lastHop=0xcc, SNR=13.0, RSSI=-71, payload=36 bytes -[2026-02-20T17:24:44.896722] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 -[2026-02-20T17:24:45.484095] LOG: [CONN] Frame received (76 bytes): 88 32 b6 05 03 86 7e dd bf be b8 0c 2b 14 d5 4c 6c 3f 92 45 98 d1 d2 3e 11 24 b8 33 9b ff e0 87 8d dc 7b ab 69 e0 56 68 3f 8c 40 ce 61 ec 4a d3 d7 bf 6f 13 af 2a d5 10 8f 2c bd 63 2c fb 87 91 ca 71 93 71 6e da 77 b6 7a 4f 48 e2 -[2026-02-20T17:24:45.484275] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:45.484316] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:45.484390] LOG: [RX PARSE] RAW Packet (73 bytes): 05 03 86 7E DD BF BE B8 0C 2B 14 D5 4C 6C 3F 92 45 98 D1 D2 3E 11 24 B8 33 9B FF E0 87 8D DC 7B AB 69 E0 56 68 3F 8C 40 CE 61 EC 4A D3 D7 BF 6F 13 AF 2A D5 10 8F 2C BD 63 2C FB 87 91 CA 71 93 71 6E DA 77 B6 7A 4F 48 E2 -[2026-02-20T17:24:45.484407] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:45.484423] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T17:24:45.484451] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x86, lastHop=0xdd, SNR=12.5, RSSI=-74, payload=68 bytes -[2026-02-20T17:24:45.484466] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 -[2026-02-20T17:24:46.174304] LOG: [CONN] Frame received (76 bytes): 88 2e b8 05 03 86 7e cc bf be b8 0c 2b 14 d5 4c 6c 3f 92 45 98 d1 d2 3e 11 24 b8 33 9b ff e0 87 8d dc 7b ab 69 e0 56 68 3f 8c 40 ce 61 ec 4a d3 d7 bf 6f 13 af 2a d5 10 8f 2c bd 63 2c fb 87 91 ca 71 93 71 6e da 77 b6 7a 4f 48 e2 -[2026-02-20T17:24:46.174476] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:46.174590] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:46.174679] LOG: [RX PARSE] RAW Packet (73 bytes): 05 03 86 7E CC BF BE B8 0C 2B 14 D5 4C 6C 3F 92 45 98 D1 D2 3E 11 24 B8 33 9B FF E0 87 8D DC 7B AB 69 E0 56 68 3F 8C 40 CE 61 EC 4A D3 D7 BF 6F 13 AF 2A D5 10 8F 2C BD 63 2C FB 87 91 CA 71 93 71 6E DA 77 B6 7A 4F 48 E2 -[2026-02-20T17:24:46.174695] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:46.174712] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T17:24:46.174738] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=3, firstHop=0x86, lastHop=0xcc, SNR=11.5, RSSI=-72, payload=68 bytes -[2026-02-20T17:24:46.174757] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=3 -[2026-02-20T17:24:48.487786] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:48.616450] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 2e 04 00 00 00 d5 22 00 00 -[2026-02-20T17:24:48.616580] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:48.616600] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:24:50.396122] LOG: [CONN] Frame received (49 bytes): 88 31 bb 05 11 24 7e 75 20 20 20 20 20 20 20 20 20 53 c7 32 9b cc bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b -[2026-02-20T17:24:50.396199] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:50.396217] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:50.396239] LOG: [RX PARSE] RAW Packet (46 bytes): 05 11 24 7E 75 20 20 20 20 20 20 20 20 20 53 C7 32 9B CC BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B -[2026-02-20T17:24:50.396244] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:50.396251] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T17:24:50.396268] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=17, firstHop=0x24, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=27 bytes -[2026-02-20T17:24:50.396275] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=17 -[2026-02-20T17:24:50.939451] LOG: [CONN] Frame received (49 bytes): 88 33 b8 05 11 24 7e 75 20 20 20 20 20 20 20 20 20 53 c7 32 2a dd bf be c3 29 4f e2 7e fb 64 ee 73 1d ca 29 3a c9 c3 40 fa 64 94 96 fe 8b 1c 2d 8b -[2026-02-20T17:24:50.939621] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:24:50.939653] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:24:50.939707] LOG: [RX PARSE] RAW Packet (46 bytes): 05 11 24 7E 75 20 20 20 20 20 20 20 20 20 53 C7 32 2A DD BF BE C3 29 4F E2 7E FB 64 EE 73 1D CA 29 3A C9 C3 40 FA 64 94 96 FE 8B 1C 2D 8B -[2026-02-20T17:24:50.939722] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T17:24:50.939734] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T17:24:50.939770] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=17, firstHop=0x24, lastHop=0xdd, SNR=12.75, RSSI=-72, payload=27 bytes -[2026-02-20T17:24:50.939784] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=17 -[2026-02-20T17:24:53.487354] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:53.536457] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 33 04 00 00 00 d5 22 00 00 -[2026-02-20T17:24:53.536578] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:53.536605] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:24:56.427799] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:24:56.427916] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:24:58.486922] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:24:58.576118] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 33 04 00 00 00 d5 22 00 00 -[2026-02-20T17:24:58.576220] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:24:58.576245] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:01.708369] LOG: [CONN] Frame received (47 bytes): 88 30 b8 15 07 8b 17 9d 32 74 7e dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b 1b 13 c4 -[2026-02-20T17:25:01.708387] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:01.708401] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:01.708410] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 8B 17 9D 32 74 7E DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B 1B 13 C4 -[2026-02-20T17:25:01.708413] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:01.708417] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T17:25:01.708427] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x8b, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=35 bytes -[2026-02-20T17:25:01.708433] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T17:25:02.551164] LOG: [CONN] Frame received (48 bytes): 88 2f bb 15 08 8b 17 9d 32 74 7e dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b 1b 13 c4 -[2026-02-20T17:25:02.551213] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:02.551224] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:02.551234] LOG: [RX PARSE] RAW Packet (45 bytes): 15 08 8B 17 9D 32 74 7E DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B 1B 13 C4 -[2026-02-20T17:25:02.551236] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:02.551240] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T17:25:02.551246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x8b, lastHop=0xcc, SNR=11.75, RSSI=-69, payload=35 bytes -[2026-02-20T17:25:02.551250] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T17:25:03.486820] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:25:03.487007] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:03.644406] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:25:03.644447] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:25:03.644454] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:25:03.644463] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T17:25:03.734645] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bb 2f 04 00 00 00 d5 22 00 00 -[2026-02-20T17:25:03.734687] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:03.734693] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:07.279047] LOG: [CONN] Frame received (58 bytes): 88 31 b9 15 15 8b 17 9d 32 74 7e 75 20 20 20 20 75 e9 24 08 7a cf 9d 32 2a dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b -[2026-02-20T17:25:07.279106] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:07.279149] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:07.279210] LOG: [RX PARSE] RAW Packet (55 bytes): 15 15 8B 17 9D 32 74 7E 75 20 20 20 20 75 E9 24 08 7A CF 9D 32 2A DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B -[2026-02-20T17:25:07.279227] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:07.279245] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T17:25:07.279270] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x8b, lastHop=0xdd, SNR=12.25, RSSI=-71, payload=32 bytes -[2026-02-20T17:25:07.279290] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T17:25:07.681177] LOG: [CONN] Frame received (59 bytes): 88 31 b8 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 75 e9 24 08 7a cf 9d 32 2a dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d bc 4b -[2026-02-20T17:25:07.681296] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:07.681329] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:07.681387] LOG: [RX PARSE] RAW Packet (56 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 75 E9 24 08 7A CF 9D 32 2A DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D BC 4B -[2026-02-20T17:25:07.681417] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:07.681429] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T17:25:07.681454] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xcc, SNR=12.25, RSSI=-72, payload=32 bytes -[2026-02-20T17:25:07.681469] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T17:25:08.487760] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:08.626720] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 31 04 00 00 00 d6 22 00 00 -[2026-02-20T17:25:08.626847] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:08.626867] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:25:09.874123] LOG: [CONN] Frame received (51 bytes): 88 2f b9 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 -[2026-02-20T17:25:09.874248] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:09.874285] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:09.874347] LOG: [RX PARSE] RAW Packet (48 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 -[2026-02-20T17:25:09.874363] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:09.874380] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T17:25:09.874405] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=24 bytes -[2026-02-20T17:25:09.874425] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T17:25:10.414359] LOG: [CONN] Frame received (51 bytes): 88 32 b9 15 16 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7e cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 -[2026-02-20T17:25:10.414501] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:10.414637] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:10.414697] LOG: [RX PARSE] RAW Packet (48 bytes): 15 16 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 -[2026-02-20T17:25:10.414713] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:10.414731] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T17:25:10.414757] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x8b, lastHop=0xcc, SNR=12.5, RSSI=-71, payload=24 bytes -[2026-02-20T17:25:10.414771] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T17:25:10.757695] LOG: [CONN] Frame received (55 bytes): 88 2f b9 15 14 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 75 24 5f 53 7e 2a dd ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d -[2026-02-20T17:25:10.757974] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:10.758007] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:10.758119] LOG: [RX PARSE] RAW Packet (52 bytes): 15 14 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 75 24 5F 53 7E 2A DD CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D -[2026-02-20T17:25:10.758136] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:10.758152] LOG: [RX PARSE] Path length offset: 1, Path length: 20 -[2026-02-20T17:25:10.758179] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=20, firstHop=0x8b, lastHop=0xdd, SNR=11.75, RSSI=-71, payload=30 bytes -[2026-02-20T17:25:10.758194] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=20 -[2026-02-20T17:25:11.163067] LOG: [CONN] Frame received (56 bytes): 88 30 b8 15 15 8b 17 9d 32 74 7e 75 20 20 20 20 20 20 75 24 5f 53 7e 2a dd cc ca d0 96 78 5e 38 32 80 5a 83 7f dc 9b e6 a9 30 e1 32 5d 84 e3 f9 78 f1 a8 09 ba 74 8e 2d -[2026-02-20T17:25:11.163203] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:11.163232] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:11.163291] LOG: [RX PARSE] RAW Packet (53 bytes): 15 15 8B 17 9D 32 74 7E 75 20 20 20 20 20 20 75 24 5F 53 7E 2A DD CC CA D0 96 78 5E 38 32 80 5A 83 7F DC 9B E6 A9 30 E1 32 5D 84 E3 F9 78 F1 A8 09 BA 74 8E 2D -[2026-02-20T17:25:11.163306] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:11.163321] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T17:25:11.163344] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x8b, lastHop=0xcc, SNR=12.0, RSSI=-72, payload=30 bytes -[2026-02-20T17:25:11.163358] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T17:25:11.427979] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:25:11.428103] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:25:13.487568] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:13.636351] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:13.636470] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:13.636492] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:18.487021] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:18.646492] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:18.646609] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:18.646620] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:23.487645] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:23.656766] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 30 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:23.656890] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:23.656911] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:26.430179] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:25:26.432454] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:25:27.102344] LOG: [APP] App resumed from background -[2026-02-20T17:25:28.486764] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:28.546103] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 30 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:28.546192] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:28.546223] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:25:29.658674] LOG: [CONN] Frame received (108 bytes): 88 30 b8 15 04 01 7a 7e dd 11 19 8d bf c6 7d 08 bb 7a 45 f5 92 32 cc 23 54 36 99 6e bf 07 8b 6c d6 39 82 d5 09 9f cf 33 de 18 ae ab 4f d6 3e 7a 71 30 90 ca e2 fe 77 08 c5 c1 18 7b 7f ef be fa 54 35 11 b6 45 7e b9 74 41 31 7a c1 a4 fa 46 15 1a 71 a1 ff f0 b4 29 03 cb 80 75 db f5 da 10 79 aa 03 9a 69 a7 d3 a3 ba fe 02 f1 c6 -[2026-02-20T17:25:29.658934] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:29.659104] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:29.659196] LOG: [RX PARSE] RAW Packet (105 bytes): 15 04 01 7A 7E DD 11 19 8D BF C6 7D 08 BB 7A 45 F5 92 32 CC 23 54 36 99 6E BF 07 8B 6C D6 39 82 D5 09 9F CF 33 DE 18 AE AB 4F D6 3E 7A 71 30 90 CA E2 FE 77 08 C5 C1 18 7B 7F EF BE FA 54 35 11 B6 45 7E B9 74 41 31 7A C1 A4 FA 46 15 1A 71 A1 FF F0 B4 29 03 CB 80 75 DB F5 DA 10 79 AA 03 9A 69 A7 D3 A3 BA FE 02 F1 C6 -[2026-02-20T17:25:29.659220] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:29.659304] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T17:25:29.660089] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x01, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=99 bytes -[2026-02-20T17:25:29.660146] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T17:25:29.660665] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T17:25:29.660678] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T17:25:29.660690] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T17:25:31.638278] LOG: [CONN] Frame received (109 bytes): 88 2f b8 15 05 01 7a 7e dd cc 11 19 8d bf c6 7d 08 bb 7a 45 f5 92 32 cc 23 54 36 99 6e bf 07 8b 6c d6 39 82 d5 09 9f cf 33 de 18 ae ab 4f d6 3e 7a 71 30 90 ca e2 fe 77 08 c5 c1 18 7b 7f ef be fa 54 35 11 b6 45 7e b9 74 41 31 7a c1 a4 fa 46 15 1a 71 a1 ff f0 b4 29 03 cb 80 75 db f5 da 10 79 aa 03 9a 69 a7 d3 a3 ba fe 02 f1 c6 -[2026-02-20T17:25:31.638414] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:31.638459] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:31.638651] LOG: [RX PARSE] RAW Packet (106 bytes): 15 05 01 7A 7E DD CC 11 19 8D BF C6 7D 08 BB 7A 45 F5 92 32 CC 23 54 36 99 6E BF 07 8B 6C D6 39 82 D5 09 9F CF 33 DE 18 AE AB 4F D6 3E 7A 71 30 90 CA E2 FE 77 08 C5 C1 18 7B 7F EF BE FA 54 35 11 B6 45 7E B9 74 41 31 7A C1 A4 FA 46 15 1A 71 A1 FF F0 B4 29 03 CB 80 75 DB F5 DA 10 79 AA 03 9A 69 A7 D3 A3 BA FE 02 F1 C6 -[2026-02-20T17:25:31.638667] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:31.638679] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T17:25:31.638735] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x01, lastHop=0xcc, SNR=11.75, RSSI=-72, payload=99 bytes -[2026-02-20T17:25:31.638750] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T17:25:33.487078] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:25:33.487967] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:33.650447] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:25:33.650623] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:25:33.650701] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:25:33.650801] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T17:25:33.705385] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 2f 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:33.705443] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:33.705451] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:38.487046] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:38.566907] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b8 2f 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:38.567029] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:38.567057] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:25:41.428109] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:25:41.428251] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:25:43.486951] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:43.608947] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff b8 2f 04 00 00 00 d7 22 00 00 -[2026-02-20T17:25:43.609081] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:43.609179] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:25:46.743942] LOG: [CONN] Frame received (124 bytes): 88 33 b7 15 04 1f 7e 2a dd 72 5f 69 23 41 93 cc 75 8f 30 17 3a 4f 17 74 c9 d8 c9 ec 3c 83 dc 91 5b 64 07 a7 6e 96 80 67 c6 9b cb 8d e1 b5 de 68 51 1c 2b 23 63 07 c5 47 6e a0 15 df ea c1 67 bf d5 17 cf 5b 10 5a 55 24 61 cb f1 8b d9 c6 83 04 fb 89 45 6b 00 ad 85 1c c2 26 15 24 8c 15 1a 6d 96 53 93 b8 77 4c 0a a6 b5 7e a1 91 1d 26 87 98 de 9e 95 28 6e f2 6e 2d 75 ba 23 b8 -[2026-02-20T17:25:46.743989] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:46.744026] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:46.744076] LOG: [RX PARSE] RAW Packet (121 bytes): 15 04 1F 7E 2A DD 72 5F 69 23 41 93 CC 75 8F 30 17 3A 4F 17 74 C9 D8 C9 EC 3C 83 DC 91 5B 64 07 A7 6E 96 80 67 C6 9B CB 8D E1 B5 DE 68 51 1C 2B 23 63 07 C5 47 6E A0 15 DF EA C1 67 BF D5 17 CF 5B 10 5A 55 24 61 CB F1 8B D9 C6 83 04 FB 89 45 6B 00 AD 85 1C C2 26 15 24 8C 15 1A 6D 96 53 93 B8 77 4C 0A A6 B5 7E A1 91 1D 26 87 98 DE 9E 95 28 6E F2 6E 2D 75 BA 23 B8 -[2026-02-20T17:25:46.744139] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:46.744145] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T17:25:46.744192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x1f, lastHop=0xdd, SNR=12.75, RSSI=-73, payload=115 bytes -[2026-02-20T17:25:46.744199] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T17:25:47.618583] LOG: [APP] App resumed from background -[2026-02-20T17:25:47.702006] LOG: [CONN] Frame received (125 bytes): 88 31 ba 15 05 1f 7e 2a dd cc 72 5f 69 23 41 93 cc 75 8f 30 17 3a 4f 17 74 c9 d8 c9 ec 3c 83 dc 91 5b 64 07 a7 6e 96 80 67 c6 9b cb 8d e1 b5 de 68 51 1c 2b 23 63 07 c5 47 6e a0 15 df ea c1 67 bf d5 17 cf 5b 10 5a 55 24 61 cb f1 8b d9 c6 83 04 fb 89 45 6b 00 ad 85 1c c2 26 15 24 8c 15 1a 6d 96 53 93 b8 77 4c 0a a6 b5 7e a1 91 1d 26 87 98 de 9e 95 28 6e f2 6e 2d 75 ba 23 b8 -[2026-02-20T17:25:47.702059] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:47.702075] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:47.702109] LOG: [RX PARSE] RAW Packet (122 bytes): 15 05 1F 7E 2A DD CC 72 5F 69 23 41 93 CC 75 8F 30 17 3A 4F 17 74 C9 D8 C9 EC 3C 83 DC 91 5B 64 07 A7 6E 96 80 67 C6 9B CB 8D E1 B5 DE 68 51 1C 2B 23 63 07 C5 47 6E A0 15 DF EA C1 67 BF D5 17 CF 5B 10 5A 55 24 61 CB F1 8B D9 C6 83 04 FB 89 45 6B 00 AD 85 1C C2 26 15 24 8C 15 1A 6D 96 53 93 B8 77 4C 0A A6 B5 7E A1 91 1D 26 87 98 DE 9E 95 28 6E F2 6E 2D 75 BA 23 B8 -[2026-02-20T17:25:47.702113] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:47.702117] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T17:25:47.702123] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-70, payload=115 bytes -[2026-02-20T17:25:47.702127] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T17:25:48.487006] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:48.645542] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff ba 31 04 00 00 00 d8 22 00 00 -[2026-02-20T17:25:48.645643] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:48.645655] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T17:25:49.294478] LOG: [CONN] Frame received (51 bytes): 88 31 b9 15 15 4d 13 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e dd 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 -[2026-02-20T17:25:49.294789] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:49.294826] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:49.294878] LOG: [RX PARSE] RAW Packet (48 bytes): 15 15 4D 13 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E DD 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 -[2026-02-20T17:25:49.294898] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:49.294909] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T17:25:49.294991] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x4d, lastHop=0xdd, SNR=12.25, RSSI=-71, payload=25 bytes -[2026-02-20T17:25:49.295006] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T17:25:49.955720] LOG: [CONN] Frame received (51 bytes): 88 2f ba 15 15 4d 13 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e cc 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 -[2026-02-20T17:25:49.955871] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:49.955909] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:49.955959] LOG: [RX PARSE] RAW Packet (48 bytes): 15 15 4D 13 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 -[2026-02-20T17:25:49.955974] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:49.955989] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T17:25:49.956012] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x4d, lastHop=0xcc, SNR=11.75, RSSI=-70, payload=25 bytes -[2026-02-20T17:25:49.956041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T17:25:52.086269] LOG: [CONN] Frame received (49 bytes): 88 30 b8 15 0a 4d 13 c7 7e 75 20 20 53 86 dd 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 a3 05 f5 00 77 28 d5 11 71 -[2026-02-20T17:25:52.086335] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:52.086388] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:52.086695] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0A 4D 13 C7 7E 75 20 20 53 86 DD 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 A3 05 F5 00 77 28 D5 11 71 -[2026-02-20T17:25:52.086734] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:52.086837] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T17:25:52.086867] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x4d, lastHop=0xdd, SNR=12.0, RSSI=-72, payload=34 bytes -[2026-02-20T17:25:52.086882] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T17:25:53.375359] LOG: [CONN] Frame received (50 bytes): 88 32 ba 15 0b 4d 13 c7 7e 75 20 20 53 86 dd cc 72 9c cb 25 c7 ea 55 92 d9 94 d8 b5 37 80 ea e7 10 43 ab 8e ca 26 90 29 17 a3 05 f5 00 77 28 d5 11 71 -[2026-02-20T17:25:53.375622] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:25:53.375657] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:25:53.375716] LOG: [RX PARSE] RAW Packet (47 bytes): 15 0B 4D 13 C7 7E 75 20 20 53 86 DD CC 72 9C CB 25 C7 EA 55 92 D9 94 D8 B5 37 80 EA E7 10 43 AB 8E CA 26 90 29 17 A3 05 F5 00 77 28 D5 11 71 -[2026-02-20T17:25:53.375732] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:25:53.375742] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T17:25:53.375775] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x4d, lastHop=0xcc, SNR=12.5, RSSI=-70, payload=34 bytes -[2026-02-20T17:25:53.375789] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T17:25:53.486846] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:25:53.567225] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff ba 32 04 00 00 00 d9 22 00 00 -[2026-02-20T17:25:53.567341] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:25:53.567362] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T17:25:56.427822] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:25:56.427963] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:25:56.941329] LOG: [HEARTBEAT] Heartbeat mode disabled -[2026-02-20T17:25:56.941442] LOG: [BACKGROUND] Service not running -[2026-02-20T17:25:56.941481] LOG: [RX LOG] Stopping passive RX wardriving: trigger=disconnect -[2026-02-20T17:25:56.941501] LOG: [RX BATCH] Flushing all repeaters, trigger=disconnect, active_repeaters=0 -[2026-02-20T17:25:56.941504] LOG: [RX BATCH] No repeaters to flush -[2026-02-20T17:25:56.941509] LOG: [API QUEUE] Timers stopped on disconnect -[2026-02-20T17:25:56.943876] LOG: [APP] Releasing API session -[2026-02-20T17:25:57.657158] LOG: [API] POST /wardrive-api.php/auth -[2026-02-20T17:25:57.657193] LOG: [API] Request: {"reason":"disconnect"} -[2026-02-20T17:25:57.657210] LOG: [API] Response (200) in 0.71s: {"success":true,"disconnected":true} -[2026-02-20T17:25:57.657216] LOG: [API] Session cleared -[2026-02-20T17:25:57.657221] LOG: [APP] API session released successfully -[2026-02-20T17:25:57.827724] LOG: [CHANNEL] Deleting channel at index 2 -[2026-02-20T17:25:57.828007] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:25:57.828012] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:25:57.828030] LOG: [CONN] Received OK response -[2026-02-20T17:25:57.884539] LOG: [CHANNEL] Channel deleted successfully -[2026-02-20T17:25:57.884600] LOG: [UNIFIED RX] Disposing unified handler -[2026-02-20T17:25:57.884605] LOG: [UNIFIED RX] Stopping unified RX listening -[2026-02-20T17:25:57.884619] LOG: [UNIFIED RX] ✅ Unified listening stopped -[2026-02-20T17:25:57.884627] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T17:25:57.884630] LOG: [RX LOG] Disposing RX Logger -[2026-02-20T17:25:57.884637] LOG: [CONN] Disconnecting -[2026-02-20T17:25:57.884680] LOG: [CONN] Stopped noise floor polling -[2026-02-20T17:25:57.884697] LOG: [CONN] Stopped battery polling -[2026-02-20T17:25:57.888563] LOG: [BLE] Connection state changed: BluetoothConnectionState.disconnected -[2026-02-20T17:25:57.888624] LOG: [CONN] Step: ConnectionStep.disconnected -[2026-02-20T17:25:57.888643] LOG: [CONN] Disconnected successfully -[2026-02-20T17:25:57.888657] LOG: [HEARTBEAT] Heartbeat mode disabled -[2026-02-20T17:25:57.888660] LOG: [CONN] Heartbeat disabled due to BLE disconnect -[2026-02-20T17:25:57.888689] LOG: [API QUEUE] Timers stopped on disconnect -[2026-02-20T17:25:57.888701] LOG: [CONN] Stopped noise floor polling -[2026-02-20T17:25:57.888706] LOG: [CONN] Stopped battery polling -[2026-02-20T17:25:57.888710] LOG: [DISC] Stopping discovery mode -[2026-02-20T17:25:57.888736] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:25:57.888751] LOG: [CHANNEL] Clearing regional channels -[2026-02-20T17:25:57.888774] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:25:57.891285] LOG: [APP] Saved preferences -[2026-02-20T17:59:16.370817] LOG: [GPS SERVICE] Position stream fired: lat=47.33704, lon=-122.22633, accuracy=600.0m -[2026-02-20T17:59:16.371592] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:59:16.371689] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone -[2026-02-20T17:59:16.371699] LOG: [GEOFENCE] checkZoneStatus() called -[2026-02-20T17:59:16.371883] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked -[2026-02-20T17:59:16.371895] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) -[2026-02-20T17:59:16.371929] LOG: [GEOFENCE] Making API call to check zone at 47.33704, -122.22633 (accuracy: 600.0m) -[2026-02-20T17:59:16.373392] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:59:16.425483] LOG: [APP] App resumed from background -[2026-02-20T17:59:16.767394] ERROR: ❌ [API] /wardrive-api.php/status returned HTTP 403 -[2026-02-20T17:59:16.767536] ERROR: ❌ [API] Response body: {"success":false,"reason":"gps_inaccurate","message":"GPS accuracy exceeds 50 meter threshold"} -[2026-02-20T17:59:16.767556] ERROR: ❌ [API] Response headers: {connection: Keep-Alive, access-control-allow-headers: Content-Type, alt-svc: h3=":443"; ma=2592000, h3-29=":443"; ma=2592000, h3-Q050=":443"; ma=2592000, h3-Q046=":443"; ma=2592000, h3-Q043=":443"; ma=2592000, quic=":443"; ma=2592000; v="43,46", keep-alive: timeout=5, max=100, date: Sat, 21 Feb 2026 01:59:16 GMT, access-control-allow-origin: *, vary: Accept-Encoding, content-encoding: gzip, access-control-allow-methods: POST, OPTIONS, content-length: 107, content-type: application/json; charset=UTF-8, server: LiteSpeed} -[2026-02-20T17:59:16.767630] LOG: [API] POST /wardrive-api.php/status -[2026-02-20T17:59:16.767636] LOG: [API] Request: {"lat":47.3370382,"lng":-122.2263281,"accuracy_m":600.0,"ver":"APP-1771555184","timestamp":1771639156} -[2026-02-20T17:59:16.767645] LOG: [API] Response (403) in 0.40s: {"success":false,"reason":"gps_inaccurate","message":"GPS accuracy exceeds 50 meter threshold"} -[2026-02-20T17:59:16.767653] LOG: [GEOFENCE] API response received: valid -[2026-02-20T17:59:16.767665] ERROR: ❌ [GEOFENCE] Zone status check failed: reason=gps_inaccurate, message=GPS accuracy exceeds 50 meter threshold -[2026-02-20T17:59:16.767729] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA -[2026-02-20T17:59:17.016304] LOG: [GPS SERVICE] Position stream fired: lat=47.33792, lon=-122.22475, accuracy=3.8m -[2026-02-20T17:59:17.016387] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone -[2026-02-20T17:59:17.016392] LOG: [GEOFENCE] checkZoneStatus() called -[2026-02-20T17:59:17.016398] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked -[2026-02-20T17:59:17.016403] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) -[2026-02-20T17:59:17.016409] LOG: [GEOFENCE] Making API call to check zone at 47.33792, -122.22475 (accuracy: 3.8m) -[2026-02-20T17:59:17.212738] LOG: [API] POST /wardrive-api.php/status -[2026-02-20T17:59:17.212772] LOG: [API] Request: {"lat":47.337924,"lng":-122.2247485,"accuracy_m":3.7899999618530273,"ver":"APP-1771555184","timestamp":1771639157} -[2026-02-20T17:59:17.212777] LOG: [API] Response (200) in 0.20s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":12,"slots_max":15}} -[2026-02-20T17:59:17.212784] LOG: [GEOFENCE] API response received: valid -[2026-02-20T17:59:17.212924] LOG: [GEOFENCE] In zone: Seattle, US (SEA) -[2026-02-20T17:59:17.212928] LOG: [MAP] Repeaters already loaded for zone: SEA -[2026-02-20T17:59:17.212934] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA -[2026-02-20T17:59:22.567178] LOG: [BLE] Cached device info: MeshCore-Cozmo (F3:16:AF:D8:2B:1E) -[2026-02-20T17:59:22.572753] LOG: [API QUEUE] Restarting batch timer on connect -[2026-02-20T17:59:22.572823] LOG: [APP] Creating new MeshCoreConnection -[2026-02-20T17:59:22.573151] LOG: [CONN] Step: ConnectionStep.bleConnecting -[2026-02-20T17:59:22.573171] LOG: [BLE] Connection attempt 1/3 to F3:16:AF:D8:2B:1E -[2026-02-20T17:59:22.573197] LOG: [BLE] Device reference created -[2026-02-20T17:59:22.573204] LOG: [BLE] Connecting to GATT... -[2026-02-20T17:59:22.883265] LOG: [BLE] GATT connected -[2026-02-20T17:59:23.293548] LOG: [BLE] MTU negotiated: 247 bytes -[2026-02-20T17:59:23.395022] LOG: [BLE] Discovering services... -[2026-02-20T17:59:23.714302] LOG: [BLE] Found 3 services -[2026-02-20T17:59:23.714498] LOG: [BLE] Found MeshCore service -[2026-02-20T17:59:23.714775] LOG: [BLE] Found TX characteristic -[2026-02-20T17:59:23.714832] LOG: [BLE] Found RX characteristic -[2026-02-20T17:59:23.714842] LOG: [BLE] Enabling notifications... -[2026-02-20T17:59:23.802614] LOG: [BLE] Notifications enabled -[2026-02-20T17:59:23.802763] LOG: [BLE] Device name: MeshCore-Cozmo (from scan: true, platformName: ) -[2026-02-20T17:59:23.802784] LOG: [BLE] Connection complete -[2026-02-20T17:59:23.802807] LOG: [CONN] Step: ConnectionStep.protocolHandshake -[2026-02-20T17:59:23.957428] LOG: [CONN] Frame received (79 bytes): 88 2f b4 15 07 96 a4 cd 6c 7e 9b dd 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e ee 2c 47 -[2026-02-20T17:59:23.957582] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:23.958218] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T17:59:23.958239] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T17:59:23.958250] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T17:59:24.303755] LOG: [CONN] Step: ConnectionStep.deviceQuery -[2026-02-20T17:59:24.373471] LOG: [CONN] Frame received (80 bytes): 0d 08 af 28 00 00 00 00 32 39 2d 4a 61 6e 2d 32 30 32 36 00 48 65 6c 74 65 63 20 54 31 31 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 31 2e 31 32 2e 30 2d 65 37 33 38 61 37 34 00 00 00 00 00 -[2026-02-20T17:59:24.373626] LOG: [CONN] Response code: 0x0d (13) -[2026-02-20T17:59:24.373641] LOG: [CONN] Firmware version: 8 -[2026-02-20T17:59:24.373661] LOG: [CONN] Build date: 29-Jan-2026 -[2026-02-20T17:59:24.373678] LOG: [CONN] Manufacturer model: Heltec T114v1.12.0-e738a74 -[2026-02-20T17:59:24.432798] LOG: [CONN] Frame received (63 bytes): 05 01 16 16 f9 92 6e f7 f7 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f a5 eb ab b8 d2 02 0f 1a b9 f8 00 00 00 01 bd e4 0d 00 24 f4 00 00 07 05 43 6f 7a 6d 6f -[2026-02-20T17:59:24.432931] LOG: [CONN] Response code: 0x05 (5) -[2026-02-20T17:59:24.432975] LOG: [CONN] SelfInfo received: name="Cozmo", publicKey=F9926EF7F78C5689... -[2026-02-20T17:59:24.433015] LOG: [CONN] Public key acquired: F9926EF7F78C5689... -[2026-02-20T17:59:24.433033] LOG: [CONN] Step: ConnectionStep.powerConfiguration -[2026-02-20T17:59:24.433089] LOG: [CONN] Device identified: Heltec T114 (reports 0.3W / 22dBm) -[2026-02-20T17:59:24.433108] LOG: [CONN] Step: ConnectionStep.timeSync -[2026-02-20T17:59:24.496928] LOG: [CONN] Step: ConnectionStep.slotAcquisition -[2026-02-20T17:59:24.497060] LOG: [CONN] Requesting API session via geo-auth -[2026-02-20T17:59:24.497112] LOG: [APP] Stage 1: Attempting auth with public_key: F9926EF7F78C5689... -[2026-02-20T17:59:24.500514] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:59:24.500609] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:59:24.500622] LOG: [CONN] Received OK response -[2026-02-20T17:59:24.790589] LOG: [API] POST /wardrive-api.php/auth -[2026-02-20T17:59:24.790689] LOG: [API] Request: {"reason":"connect","who":"Cozmo","ver":"APP-1771555184","power":"0.3w","iata":"SEA","model":"Heltec T114","coords":{"lat":47.337924,"lng":-122.2247485,"accuracy_m":3.7899999618530273,"timestamp":1771639164}} -[2026-02-20T17:59:24.790710] LOG: [API] Response (200) in 0.29s: {"success":true,"tx_allowed":true,"rx_allowed":true,"zone":{"name":"Seattle, US","code":"SEA"},"expires_at":1771639464,"type":"API","debug_mode":0,"enforce_hybrid":false,"min_mode_interval":15,"channels":["public","bot","bot-tacoma","olybot","bot-islands","sipesbot"]} -[2026-02-20T17:59:24.790753] LOG: [API] Regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] -[2026-02-20T17:59:24.790785] LOG: [APP] Stage 1 succeeded: authenticated via public_key -[2026-02-20T17:59:24.790796] LOG: [APP] Auth type: API -[2026-02-20T17:59:24.790815] LOG: [CONN] API session acquired successfully (session_id: SEA-20260220-0039) -[2026-02-20T17:59:24.790838] LOG: [CONN] Step: ConnectionStep.channelSetup -[2026-02-20T17:59:24.790850] LOG: [CONN] Creating #wardriving channel -[2026-02-20T17:59:24.790860] LOG: [CHANNEL] Looking up channel: #wardriving -[2026-02-20T17:59:24.790878] LOG: [CONN] getChannel(0) - sending request -[2026-02-20T17:59:24.790905] LOG: [CONN] getChannel bytes: 0x1f 0x00 -[2026-02-20T17:59:24.915217] LOG: [CONN] Frame received (50 bytes): 12 00 50 75 62 6c 69 63 00 8c 56 89 51 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 8b 33 87 e9 c5 cd ea 6a c9 e5 ed ba a1 15 cd 72 -[2026-02-20T17:59:24.915344] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:24.915391] LOG: [CONN] getChannel(1) - sending request -[2026-02-20T17:59:24.915411] LOG: [CONN] getChannel bytes: 0x1f 0x01 -[2026-02-20T17:59:24.972776] LOG: [CONN] Frame received (50 bytes): 12 01 23 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 62 e8 c7 49 22 e1 e3 9e 52 e2 2d 14 7c 9a c0 2f -[2026-02-20T17:59:24.972832] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:24.972841] LOG: [CONN] getChannel(2) - sending request -[2026-02-20T17:59:24.972844] LOG: [CONN] getChannel bytes: 0x1f 0x02 -[2026-02-20T17:59:25.031100] LOG: [CONN] Frame received (50 bytes): 12 02 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.031130] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.031136] LOG: [CHANNEL] Found empty slot at index 2 -[2026-02-20T17:59:25.031138] LOG: [CONN] getChannel(3) - sending request -[2026-02-20T17:59:25.031141] LOG: [CONN] getChannel bytes: 0x1f 0x03 -[2026-02-20T17:59:25.091174] LOG: [CONN] Frame received (50 bytes): 12 03 00 6d 61 70 6c 65 6d 65 73 68 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.091200] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.091205] LOG: [CONN] getChannel(4) - sending request -[2026-02-20T17:59:25.091208] LOG: [CONN] getChannel bytes: 0x1f 0x04 -[2026-02-20T17:59:25.151498] LOG: [CONN] Frame received (50 bytes): 12 04 23 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 83 c8 b0 19 97 65 42 65 93 8d a8 76 5c bc 7d b9 -[2026-02-20T17:59:25.151556] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.151569] LOG: [CONN] getChannel(5) - sending request -[2026-02-20T17:59:25.151573] LOG: [CONN] getChannel bytes: 0x1f 0x05 -[2026-02-20T17:59:25.212670] LOG: [CONN] Frame received (50 bytes): 12 05 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.212717] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.212729] LOG: [CONN] getChannel(6) - sending request -[2026-02-20T17:59:25.212734] LOG: [CONN] getChannel bytes: 0x1f 0x06 -[2026-02-20T17:59:25.272269] LOG: [CONN] Frame received (50 bytes): 12 06 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.272359] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.272513] LOG: [CONN] getChannel(7) - sending request -[2026-02-20T17:59:25.272518] LOG: [CONN] getChannel bytes: 0x1f 0x07 -[2026-02-20T17:59:25.331240] LOG: [CONN] Frame received (50 bytes): 12 07 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.331303] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.331315] LOG: [CONN] getChannel(8) - sending request -[2026-02-20T17:59:25.331322] LOG: [CONN] getChannel bytes: 0x1f 0x08 -[2026-02-20T17:59:25.391107] LOG: [CONN] Frame received (50 bytes): 12 08 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.391154] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.391164] LOG: [CONN] getChannel(9) - sending request -[2026-02-20T17:59:25.391170] LOG: [CONN] getChannel bytes: 0x1f 0x09 -[2026-02-20T17:59:25.451929] LOG: [CONN] Frame received (50 bytes): 12 09 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.451977] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.451987] LOG: [CONN] getChannel(10) - sending request -[2026-02-20T17:59:25.451995] LOG: [CONN] getChannel bytes: 0x1f 0x0a -[2026-02-20T17:59:25.511120] LOG: [CONN] Frame received (50 bytes): 12 0a 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.511158] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.511168] LOG: [CONN] getChannel(11) - sending request -[2026-02-20T17:59:25.511174] LOG: [CONN] getChannel bytes: 0x1f 0x0b -[2026-02-20T17:59:25.572632] LOG: [CONN] Frame received (50 bytes): 12 0b 00 68 61 6d 72 61 64 69 6f 00 00 98 04 83 c7 8d be b8 2d 1d 51 26 a9 f4 6e 74 4d 62 00 ca 1b 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.572670] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.572678] LOG: [CONN] getChannel(12) - sending request -[2026-02-20T17:59:25.572684] LOG: [CONN] getChannel bytes: 0x1f 0x0c -[2026-02-20T17:59:25.631418] LOG: [CONN] Frame received (80 bytes): 88 2d c2 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e ee 2c 47 -[2026-02-20T17:59:25.631452] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:25.632338] LOG: [CONN] Frame received (50 bytes): 12 0c 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.632364] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.632373] LOG: [CONN] getChannel(13) - sending request -[2026-02-20T17:59:25.632379] LOG: [CONN] getChannel bytes: 0x1f 0x0d -[2026-02-20T17:59:25.691078] LOG: [CONN] Frame received (50 bytes): 12 0d 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.691112] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.691122] LOG: [CONN] getChannel(14) - sending request -[2026-02-20T17:59:25.691128] LOG: [CONN] getChannel bytes: 0x1f 0x0e -[2026-02-20T17:59:25.752898] LOG: [CONN] Frame received (50 bytes): 12 0e 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.752934] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.752943] LOG: [CONN] getChannel(15) - sending request -[2026-02-20T17:59:25.752949] LOG: [CONN] getChannel bytes: 0x1f 0x0f -[2026-02-20T17:59:25.813005] LOG: [CONN] Frame received (50 bytes): 12 0f 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.813068] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.813123] LOG: [CONN] getChannel(16) - sending request -[2026-02-20T17:59:25.813133] LOG: [CONN] getChannel bytes: 0x1f 0x10 -[2026-02-20T17:59:25.871311] LOG: [CONN] Frame received (50 bytes): 12 10 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.871355] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.871370] LOG: [CONN] getChannel(17) - sending request -[2026-02-20T17:59:25.871377] LOG: [CONN] getChannel bytes: 0x1f 0x11 -[2026-02-20T17:59:25.931176] LOG: [CONN] Frame received (50 bytes): 12 11 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.931236] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.931249] LOG: [CONN] getChannel(18) - sending request -[2026-02-20T17:59:25.931255] LOG: [CONN] getChannel bytes: 0x1f 0x12 -[2026-02-20T17:59:25.991677] LOG: [CONN] Frame received (50 bytes): 12 12 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:25.991736] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:25.991749] LOG: [CONN] getChannel(19) - sending request -[2026-02-20T17:59:25.991759] LOG: [CONN] getChannel bytes: 0x1f 0x13 -[2026-02-20T17:59:26.051209] LOG: [CONN] Frame received (50 bytes): 12 13 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.051268] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.051278] LOG: [CONN] getChannel(20) - sending request -[2026-02-20T17:59:26.051287] LOG: [CONN] getChannel bytes: 0x1f 0x14 -[2026-02-20T17:59:26.111176] LOG: [CONN] Frame received (50 bytes): 12 14 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.111222] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.111232] LOG: [CONN] getChannel(21) - sending request -[2026-02-20T17:59:26.111240] LOG: [CONN] getChannel bytes: 0x1f 0x15 -[2026-02-20T17:59:26.171125] LOG: [CONN] Frame received (50 bytes): 12 15 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.171173] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.171182] LOG: [CONN] getChannel(22) - sending request -[2026-02-20T17:59:26.171190] LOG: [CONN] getChannel bytes: 0x1f 0x16 -[2026-02-20T17:59:26.231216] LOG: [CONN] Frame received (50 bytes): 12 16 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.231260] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.231270] LOG: [CONN] getChannel(23) - sending request -[2026-02-20T17:59:26.231279] LOG: [CONN] getChannel bytes: 0x1f 0x17 -[2026-02-20T17:59:26.292831] LOG: [CONN] Frame received (50 bytes): 12 17 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.292850] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.292867] LOG: [CONN] getChannel(24) - sending request -[2026-02-20T17:59:26.292874] LOG: [CONN] getChannel bytes: 0x1f 0x18 -[2026-02-20T17:59:26.351274] LOG: [CONN] Frame received (50 bytes): 12 18 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.351335] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.351347] LOG: [CONN] getChannel(25) - sending request -[2026-02-20T17:59:26.351356] LOG: [CONN] getChannel bytes: 0x1f 0x19 -[2026-02-20T17:59:26.412775] LOG: [CONN] Frame received (50 bytes): 12 19 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.412830] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.412841] LOG: [CONN] getChannel(26) - sending request -[2026-02-20T17:59:26.412849] LOG: [CONN] getChannel bytes: 0x1f 0x1a -[2026-02-20T17:59:26.471278] LOG: [CONN] Frame received (50 bytes): 12 1a 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.471339] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.471351] LOG: [CONN] getChannel(27) - sending request -[2026-02-20T17:59:26.471360] LOG: [CONN] getChannel bytes: 0x1f 0x1b -[2026-02-20T17:59:26.531374] LOG: [CONN] Frame received (50 bytes): 12 1b 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.531429] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.531440] LOG: [CONN] getChannel(28) - sending request -[2026-02-20T17:59:26.531448] LOG: [CONN] getChannel bytes: 0x1f 0x1c -[2026-02-20T17:59:26.621205] LOG: [CONN] Frame received (50 bytes): 12 1c 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.621259] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.621272] LOG: [CONN] getChannel(29) - sending request -[2026-02-20T17:59:26.621279] LOG: [CONN] getChannel bytes: 0x1f 0x1d -[2026-02-20T17:59:26.682319] LOG: [CONN] Frame received (50 bytes): 12 1d 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.682377] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.682963] LOG: [CONN] getChannel(30) - sending request -[2026-02-20T17:59:26.682972] LOG: [CONN] getChannel bytes: 0x1f 0x1e -[2026-02-20T17:59:26.741460] LOG: [CONN] Frame received (50 bytes): 12 1e 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.741511] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.741523] LOG: [CONN] getChannel(31) - sending request -[2026-02-20T17:59:26.741529] LOG: [CONN] getChannel bytes: 0x1f 0x1f -[2026-02-20T17:59:26.801319] LOG: [CONN] Frame received (50 bytes): 12 1f 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.801401] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.801414] LOG: [CONN] getChannel(32) - sending request -[2026-02-20T17:59:26.801420] LOG: [CONN] getChannel bytes: 0x1f 0x20 -[2026-02-20T17:59:26.864411] LOG: [CONN] Frame received (50 bytes): 12 20 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.864472] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.864485] LOG: [CONN] getChannel(33) - sending request -[2026-02-20T17:59:26.864492] LOG: [CONN] getChannel bytes: 0x1f 0x21 -[2026-02-20T17:59:26.921244] LOG: [CONN] Frame received (50 bytes): 12 21 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.921300] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.921314] LOG: [CONN] getChannel(34) - sending request -[2026-02-20T17:59:26.921321] LOG: [CONN] getChannel bytes: 0x1f 0x22 -[2026-02-20T17:59:26.981158] LOG: [CONN] Frame received (50 bytes): 12 22 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:26.981213] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:26.981226] LOG: [CONN] getChannel(35) - sending request -[2026-02-20T17:59:26.981232] LOG: [CONN] getChannel bytes: 0x1f 0x23 -[2026-02-20T17:59:27.041333] LOG: [CONN] Frame received (50 bytes): 12 23 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:27.041393] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:27.041404] LOG: [CONN] getChannel(36) - sending request -[2026-02-20T17:59:27.041412] LOG: [CONN] getChannel bytes: 0x1f 0x24 -[2026-02-20T17:59:27.102591] LOG: [CONN] Frame received (50 bytes): 12 24 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:27.102652] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:27.102868] LOG: [CONN] getChannel(37) - sending request -[2026-02-20T17:59:27.102877] LOG: [CONN] getChannel bytes: 0x1f 0x25 -[2026-02-20T17:59:27.161151] LOG: [CONN] Frame received (50 bytes): 12 25 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:27.161221] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:27.161231] LOG: [CONN] getChannel(38) - sending request -[2026-02-20T17:59:27.161238] LOG: [CONN] getChannel bytes: 0x1f 0x26 -[2026-02-20T17:59:27.221472] LOG: [CONN] Frame received (50 bytes): 12 26 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:27.221532] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:27.221545] LOG: [CONN] getChannel(39) - sending request -[2026-02-20T17:59:27.221553] LOG: [CONN] getChannel bytes: 0x1f 0x27 -[2026-02-20T17:59:27.281865] LOG: [CONN] Frame received (50 bytes): 12 27 00 15 08 96 a4 cd 6c 7e 9b dd cc 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2026-02-20T17:59:27.281927] LOG: [CONN] Response code: 0x12 (18) -[2026-02-20T17:59:27.281944] LOG: [CONN] getChannel(40) - sending request -[2026-02-20T17:59:27.281953] LOG: [CONN] getChannel bytes: 0x1f 0x28 -[2026-02-20T17:59:27.340789] LOG: [CONN] Frame received (2 bytes): 01 02 -[2026-02-20T17:59:27.340842] LOG: [CONN] Response code: 0x01 (1) -[2026-02-20T17:59:27.340846] LOG: [CONN] Received ERR response (error code: 2) -[2026-02-20T17:59:27.340878] LOG: [CHANNEL] Scan stopped at channel 40 (error: Exception: Command error (code 2)) -[2026-02-20T17:59:27.340881] LOG: [CHANNEL] #wardriving not found in 40 channels, creating at index 2 -[2026-02-20T17:59:27.340895] LOG: [CRYPTO] Deriving channel key for: #wardriving -[2026-02-20T17:59:27.340949] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.400580] LOG: [CHANNEL] Channel #wardriving created successfully at index 2 -[2026-02-20T17:59:27.400641] LOG: [CONN] Channel ready: #wardriving (CH:2) -[2026-02-20T17:59:27.400647] LOG: [CONN] Step: ConnectionStep.gpsInit -[2026-02-20T17:59:27.400654] LOG: [CONN] Step: ConnectionStep.connected -[2026-02-20T17:59:27.400657] LOG: [CONN] Connection workflow complete -[2026-02-20T17:59:27.400794] LOG: [APP] Device public key stored: F9926EF7F78C5689... -[2026-02-20T17:59:27.400799] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:59:27.400812] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:59:27.401053] LOG: [APP] Saved last connected device: Cozmo -[2026-02-20T17:59:27.601700] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:59:27.601836] LOG: [CONN] Started battery polling (30s interval) -[2026-02-20T17:59:27.601846] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:27.601859] LOG: [CONN] Started noise floor polling (5s interval) -[2026-02-20T17:59:27.601898] LOG: [MODEL] Device recognized: Heltec T114 - reporting 0.3W in API calls -[2026-02-20T17:59:27.601904] LOG: [APP] Creating unified RX handler -[2026-02-20T17:59:27.601915] LOG: [APP] TxTracker.carpeaterPrefix set to CC -[2026-02-20T17:59:27.601917] LOG: [APP] TxTracker.onCarpeaterDrop callback SET -[2026-02-20T17:59:27.601934] LOG: [APP] PacketValidator configured with 1 channels: Public -[2026-02-20T17:59:27.601937] LOG: [UNIFIED RX] Starting unified RX listening -[2026-02-20T17:59:27.601941] LOG: [UNIFIED RX] ✅ Unified listening started successfully -[2026-02-20T17:59:27.601945] LOG: [APP] Unified RX handler created and listening -[2026-02-20T17:59:27.602092] LOG: [CHANNEL] Setting regional channels: [public, bot, bot-tacoma, olybot, bot-islands, sipesbot] -[2026-02-20T17:59:27.602099] LOG: [CRYPTO] Deriving channel key for: #wardriving -[2026-02-20T17:59:27.602119] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602127] LOG: [CHANNEL] Added: #wardriving -> hash=129 -[2026-02-20T17:59:27.602130] LOG: [CRYPTO] Deriving channel key for: #bot -[2026-02-20T17:59:27.602137] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602141] LOG: [CHANNEL] Added: #bot -> hash=202 -[2026-02-20T17:59:27.602145] LOG: [CRYPTO] Deriving channel key for: #bot-tacoma -[2026-02-20T17:59:27.602149] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602155] LOG: [CHANNEL] Added: #bot-tacoma -> hash=5 -[2026-02-20T17:59:27.602157] LOG: [CRYPTO] Deriving channel key for: #olybot -[2026-02-20T17:59:27.602163] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602168] LOG: [CHANNEL] Added: #olybot -> hash=221 -[2026-02-20T17:59:27.602170] LOG: [CRYPTO] Deriving channel key for: #bot-islands -[2026-02-20T17:59:27.602175] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602180] LOG: [CHANNEL] Added: #bot-islands -> hash=183 -[2026-02-20T17:59:27.602183] LOG: [CRYPTO] Deriving channel key for: #sipesbot -[2026-02-20T17:59:27.602187] LOG: [CRYPTO] Channel key derived successfully (16 bytes) -[2026-02-20T17:59:27.602192] LOG: [CHANNEL] Added: #sipesbot -> hash=97 -[2026-02-20T17:59:27.602194] LOG: [CHANNEL] Total channels: 7 -[2026-02-20T17:59:27.602204] LOG: [APP] Regional channels configured: [#bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot] -[2026-02-20T17:59:27.602209] LOG: [UNIFIED RX] Validator updated with new channel configuration -[2026-02-20T17:59:27.602214] LOG: [APP] PacketValidator updated with 7 channels: Public, #wardriving, #bot, #bot-tacoma, #olybot, #bot-islands, #sipesbot -[2026-02-20T17:59:27.602217] LOG: [CONN] No regional scope — using unscoped flood -[2026-02-20T17:59:27.602223] LOG: [HIVE] Opening box "remembered_device"... -[2026-02-20T17:59:27.602350] LOG: [HIVE] Box "remembered_device" opened successfully -[2026-02-20T17:59:27.603545] LOG: [APP] Saved remembered device: MeshCore-Cozmo -[2026-02-20T17:59:27.603552] LOG: [APP] Display name set: "Cozmo" -[2026-02-20T17:59:27.603559] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:59:27.603567] LOG: [APP] Restored antenna preference for "Cozmo": external -[2026-02-20T17:59:27.603570] LOG: [CONN] Connected with full access (TX + RX allowed) -[2026-02-20T17:59:27.603578] LOG: [CONN] Ping validation after connect: PingValidation.tooCloseToLastPing -[2026-02-20T17:59:27.603585] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:59:27.603750] LOG: [APP] Saved preferences -[2026-02-20T17:59:28.710428] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T17:59:28.710772] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T17:59:28.710787] LOG: [CONN] Received OK response -[2026-02-20T17:59:28.711094] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:59:28.711104] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:59:28.711123] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:59:28.711134] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T17:59:28.711498] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2d 07 00 00 00 66 23 00 00 -[2026-02-20T17:59:28.711510] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:28.711524] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:31.198204] LOG: [CONN] Frame received (82 bytes): 88 31 b4 15 0d 96 a4 cd 6c 7e 75 20 20 20 20 53 7e dd 11 98 ab 45 f0 ac 14 fc fb 19 8c 5f 06 2b 4f 6b 0d 92 ac 8f df 5a 2b ad 80 43 5b 9c cd 35 b8 45 57 c9 a8 3f ed 79 29 a1 e2 65 7f 85 ac 66 dd 27 98 48 35 58 14 cd 23 96 10 52 5a f1 99 80 58 4e -[2026-02-20T17:59:31.198268] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:31.198279] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:31.198298] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0D 96 A4 CD 6C 7E 75 20 20 20 20 53 7E DD 11 98 AB 45 F0 AC 14 FC FB 19 8C 5F 06 2B 4F 6B 0D 92 AC 8F DF 5A 2B AD 80 43 5B 9C CD 35 B8 45 57 C9 A8 3F ED 79 29 A1 E2 65 7F 85 AC 66 DD 27 98 48 35 58 14 CD 23 96 10 52 5A F1 99 80 58 4E -[2026-02-20T17:59:31.198304] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:31.198307] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T17:59:31.198319] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x96, lastHop=0xdd, SNR=12.25, RSSI=-76, payload=64 bytes -[2026-02-20T17:59:31.198326] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T17:59:32.602667] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:32.740705] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 0e 07 00 00 00 66 23 00 00 -[2026-02-20T17:59:32.740751] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:32.740756] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T17:59:35.351227] LOG: [APP] App resumed from background -[2026-02-20T17:59:37.573702] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:59:37.573758] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:59:37.602848] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:37.662852] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 0e 07 00 00 00 66 23 00 00 -[2026-02-20T17:59:37.662918] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:37.662930] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:42.603530] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:42.673170] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 0e 07 00 00 00 66 23 00 00 -[2026-02-20T17:59:42.673293] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:42.673314] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:43.381886] LOG: [CONN] Frame received (86 bytes): 88 2d ae 15 11 b0 fb a6 b8 1f 53 20 20 20 20 c5 26 07 a5 e8 32 dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 a3 9b -[2026-02-20T17:59:43.382044] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:43.382080] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:43.382145] LOG: [RX PARSE] RAW Packet (83 bytes): 15 11 B0 FB A6 B8 1F 53 20 20 20 20 C5 26 07 A5 E8 32 DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 A3 9B -[2026-02-20T17:59:43.382171] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:43.382180] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T17:59:43.382214] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xb0, lastHop=0xdd, SNR=11.25, RSSI=-82, payload=64 bytes -[2026-02-20T17:59:43.382225] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T17:59:44.056430] LOG: [CONN] Frame received (87 bytes): 88 2d d2 15 12 b0 fb a6 b8 1f 53 20 20 20 20 c5 26 07 a5 e8 32 dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 a3 9b -[2026-02-20T17:59:44.056593] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:44.056627] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:44.056724] LOG: [RX PARSE] RAW Packet (84 bytes): 15 12 B0 FB A6 B8 1F 53 20 20 20 20 C5 26 07 A5 E8 32 DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 A3 9B -[2026-02-20T17:59:44.056743] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:44.056760] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T17:59:44.056788] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xb0, lastHop=0xcc, SNR=11.25, RSSI=-46, payload=64 bytes -[2026-02-20T17:59:44.056807] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T17:59:44.549622] LOG: [CONN] Frame received (84 bytes): 88 28 ac 15 11 b0 fb a6 b8 1f 53 20 20 20 20 20 20 53 a5 e8 32 dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 -[2026-02-20T17:59:44.549742] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:44.549764] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:44.549814] LOG: [RX PARSE] RAW Packet (81 bytes): 15 11 B0 FB A6 B8 1F 53 20 20 20 20 20 20 53 A5 E8 32 DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 -[2026-02-20T17:59:44.549884] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:44.549892] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T17:59:44.549924] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xb0, lastHop=0xdd, SNR=10.0, RSSI=-84, payload=62 bytes -[2026-02-20T17:59:44.549935] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T17:59:45.977094] LOG: [CONN] Frame received (85 bytes): 88 2e cc 15 12 b0 fb a6 b8 1f 53 20 20 20 20 20 20 53 a5 e8 32 dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 e2 -[2026-02-20T17:59:45.977267] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:45.977308] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:45.977387] LOG: [RX PARSE] RAW Packet (82 bytes): 15 12 B0 FB A6 B8 1F 53 20 20 20 20 20 20 53 A5 E8 32 DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 E2 -[2026-02-20T17:59:45.977405] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:45.977421] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T17:59:45.977456] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xb0, lastHop=0xcc, SNR=11.5, RSSI=-52, payload=62 bytes -[2026-02-20T17:59:45.977484] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T17:59:47.603198] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:47.683325] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2e 07 00 00 00 67 23 00 00 -[2026-02-20T17:59:47.683452] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:47.683473] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:47.930173] LOG: [CONN] Frame received (87 bytes): 88 2f b6 15 15 b0 fb a6 b8 1f 53 20 20 20 20 20 20 20 53 fc 7a 7e 41 32 2a dd 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 -[2026-02-20T17:59:47.930441] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:47.930480] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:47.930597] LOG: [RX PARSE] RAW Packet (84 bytes): 15 15 B0 FB A6 B8 1F 53 20 20 20 20 20 20 20 53 FC 7A 7E 41 32 2A DD 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 -[2026-02-20T17:59:47.930621] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:47.930633] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T17:59:47.930668] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xb0, lastHop=0xdd, SNR=11.75, RSSI=-74, payload=61 bytes -[2026-02-20T17:59:47.930687] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T17:59:49.401465] LOG: [CONN] Frame received (88 bytes): 88 35 cd 15 16 b0 fb a6 b8 1f 53 20 20 20 20 20 20 20 53 fc 7a 7e 41 32 2a dd cc 26 26 47 d7 0f 9f b4 e8 5c 54 ee b3 61 b8 39 5a f2 4a 4e 8f 68 3e d2 3d 5d 49 15 03 00 f3 b8 c5 82 67 f5 ec 98 f9 38 0b 59 55 16 d5 3f 3a e2 e1 22 fd 0d d0 70 06 78 eb 7a 26 ff 44 42 -[2026-02-20T17:59:49.401652] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T17:59:49.401686] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T17:59:49.401770] LOG: [RX PARSE] RAW Packet (85 bytes): 15 16 B0 FB A6 B8 1F 53 20 20 20 20 20 20 20 53 FC 7A 7E 41 32 2A DD CC 26 26 47 D7 0F 9F B4 E8 5C 54 EE B3 61 B8 39 5A F2 4A 4E 8F 68 3E D2 3D 5D 49 15 03 00 F3 B8 C5 82 67 F5 EC 98 F9 38 0B 59 55 16 D5 3F 3A E2 E1 22 FD 0D D0 70 06 78 EB 7A 26 FF 44 42 -[2026-02-20T17:59:49.401793] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T17:59:49.401810] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T17:59:49.401846] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xb0, lastHop=0xcc, SNR=13.25, RSSI=-51, payload=61 bytes -[2026-02-20T17:59:49.401860] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T17:59:52.573958] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T17:59:52.574112] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T17:59:52.602744] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:52.753327] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 -[2026-02-20T17:59:52.753449] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:52.753470] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:56.036068] LOG: [GPS SERVICE] Position stream fired: lat=47.33788, lon=-122.22497, accuracy=3.9m -[2026-02-20T17:59:56.036178] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T17:59:56.036206] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T17:59:57.603336] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T17:59:57.603539] LOG: [CONN] Fetching noise floor... -[2026-02-20T17:59:57.792015] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T17:59:57.792086] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T17:59:57.792094] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T17:59:57.792104] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T17:59:57.851355] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 -[2026-02-20T17:59:57.851420] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T17:59:57.851428] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T17:59:58.083587] LOG: [SESSION] Checking session validity via heartbeat... -[2026-02-20T17:59:58.645645] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T17:59:58.645673] LOG: [API] Request: {"heartbeat":true,"has_coords":true} -[2026-02-20T17:59:58.645677] LOG: [API] Response (200) in 0.56s: {"success":true,"expires_at":1771639498} -[2026-02-20T17:59:58.645685] LOG: [SESSION] Session is valid (expires_at: 1771639498) -[2026-02-20T17:59:58.645695] LOG: [PING] Starting auto mode: active -[2026-02-20T17:59:58.645698] LOG: [PING] Auto-ping interval set to 30000ms -[2026-02-20T17:59:58.645703] LOG: [PING] Using interval from preferences: 30s (30000ms) -[2026-02-20T17:59:58.645706] LOG: [AUTO] enableAutoPing called (passiveMode=false, hybridMode=false) -[2026-02-20T17:59:58.645708] LOG: [AUTO] Acquiring wake lock for auto mode -[2026-02-20T17:59:58.648180] LOG: [WAKELOCK] Screen wake lock enabled -[2026-02-20T17:59:58.648185] LOG: [ACTIVE MODE] Sending initial auto ping -[2026-02-20T17:59:58.648188] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T17:59:58.648196] LOG: [PING] Auto ping blocked: too close to last ping, scheduling next -[2026-02-20T17:59:58.648199] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T17:59:58.648240] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T17:59:58.648244] LOG: [RX LOG] Starting passive RX wardriving -[2026-02-20T17:59:58.648330] LOG: [GRAPH] Started active noise floor session -[2026-02-20T17:59:58.648335] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T17:59:58.648338] LOG: [HEARTBEAT] Heartbeat mode enabled -[2026-02-20T17:59:58.648342] LOG: [HEARTBEAT] Enabled for active Mode -[2026-02-20T17:59:58.648346] LOG: [BACKGROUND] Starting background service (mode: Active Mode) -[2026-02-20T17:59:58.652557] LOG: [BACKGROUND] Background service started -[2026-02-20T18:00:01.044693] LOG: [GPS SERVICE] Position stream fired: lat=47.33788, lon=-122.22521, accuracy=3.9m -[2026-02-20T18:00:02.602649] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:02.712135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 -[2026-02-20T18:00:02.712187] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:02.712193] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:06.042456] LOG: [GPS SERVICE] Position stream fired: lat=47.33785, lon=-122.22558, accuracy=4.5m -[2026-02-20T18:00:07.573762] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:00:07.573845] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:00:07.602885] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:07.723066] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cd 35 07 00 00 00 68 23 00 00 -[2026-02-20T18:00:07.723143] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:07.723151] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:10.233255] LOG: [CONN] Frame received (68 bytes): 88 2f ac 15 0c 88 82 b5 ba 56 a1 e3 28 aa cd 7e dd 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 1b 69 -[2026-02-20T18:00:10.233399] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:10.233430] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:10.233499] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:10.233515] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:10.233532] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:00:10.233553] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x88, lastHop=0xdd, SNR=11.75, RSSI=-84, payload=51 bytes -[2026-02-20T18:00:10.233580] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:00:10.233591] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:10.233601] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:10.233665] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:10.233681] LOG: [RX FILTER] Raw packet (65 bytes): 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:10.233699] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 -[2026-02-20T18:00:10.233718] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) -[2026-02-20T18:00:10.233731] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:10.233741] LOG: [RX FILTER] Channel hash: 0x69 -[2026-02-20T18:00:10.233757] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 -[2026-02-20T18:00:10.233843] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:00:10.233855] LOG: [RX LOG] Dropped packet hex: 15 0C 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:11.052970] LOG: [GPS SERVICE] Position stream fired: lat=47.33781, lon=-122.22599, accuracy=4.6m -[2026-02-20T18:00:11.061132] LOG: [CONN] Frame received (69 bytes): 88 31 cc 15 0d 88 82 b5 ba 56 a1 e3 28 aa cd 7e dd cc 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 1b 69 -[2026-02-20T18:00:11.061202] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:11.061212] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:11.061229] LOG: [RX PARSE] RAW Packet (66 bytes): 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:11.061232] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:11.061236] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:00:11.061243] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x88, lastHop=0xcc, SNR=12.25, RSSI=-52, payload=51 bytes -[2026-02-20T18:00:11.061246] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:00:11.061260] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:11.061262] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:11.061276] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:11.061278] LOG: [RX FILTER] Raw packet (66 bytes): 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:11.061284] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 -[2026-02-20T18:00:11.061287] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:00:11.061291] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:11.061294] LOG: [RX FILTER] Channel hash: 0x69 -[2026-02-20T18:00:11.061297] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 -[2026-02-20T18:00:11.061317] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:00:11.061319] LOG: [RX LOG] Dropped packet hex: 15 0D 88 82 B5 BA 56 A1 E3 28 AA CD 7E DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 1B 69 -[2026-02-20T18:00:12.604381] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:12.763844] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 07 00 00 00 69 23 00 00 -[2026-02-20T18:00:12.763934] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:12.763945] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:15.838362] LOG: [CONN] Frame received (72 bytes): 88 2e ac 15 12 88 82 b5 ba 56 a1 e3 28 aa cd 7e 53 20 20 20 53 86 dd 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 -[2026-02-20T18:00:15.838437] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:15.838452] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:15.838475] LOG: [RX PARSE] RAW Packet (69 bytes): 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:15.838480] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:15.838485] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:00:15.838495] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x88, lastHop=0xdd, SNR=11.5, RSSI=-84, payload=49 bytes -[2026-02-20T18:00:15.838501] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T18:00:15.838505] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:15.838508] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:15.838542] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:15.838547] LOG: [RX FILTER] Raw packet (69 bytes): 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:15.838553] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 11.5 -[2026-02-20T18:00:15.838558] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) -[2026-02-20T18:00:15.838564] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:15.838567] LOG: [RX FILTER] Channel hash: 0x69 -[2026-02-20T18:00:15.838572] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 -[2026-02-20T18:00:15.838597] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:00:15.838601] LOG: [RX LOG] Dropped packet hex: 15 12 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:16.049268] LOG: [GPS SERVICE] Position stream fired: lat=47.33781, lon=-122.22632, accuracy=4.2m -[2026-02-20T18:00:16.995160] LOG: [CONN] Frame received (73 bytes): 88 2e cc 15 13 88 82 b5 ba 56 a1 e3 28 aa cd 7e 53 20 20 20 53 86 dd cc 69 aa cf d3 be 8b 02 84 7b 94 54 80 86 12 0a 1e 8f 80 61 29 b2 06 61 56 88 32 87 73 15 ac e2 58 e0 9e 90 6a 05 a1 cd 5c 66 5c db e5 86 06 b0 79 d6 -[2026-02-20T18:00:16.995186] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:16.995207] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:16.995231] LOG: [RX PARSE] RAW Packet (70 bytes): 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:16.995238] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:16.995243] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:00:16.995256] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x88, lastHop=0xcc, SNR=11.5, RSSI=-52, payload=49 bytes -[2026-02-20T18:00:16.995262] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:00:16.995271] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:16.995274] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:16.995298] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:16.995303] LOG: [RX FILTER] Raw packet (70 bytes): 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:16.995311] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 11.5 -[2026-02-20T18:00:16.995317] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:00:16.995322] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:16.995328] LOG: [RX FILTER] Channel hash: 0x69 -[2026-02-20T18:00:16.995332] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x69 -[2026-02-20T18:00:16.995440] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:00:16.995445] LOG: [RX LOG] Dropped packet hex: 15 13 88 82 B5 BA 56 A1 E3 28 AA CD 7E 53 20 20 20 53 86 DD CC 69 AA CF D3 BE 8B 02 84 7B 94 54 80 86 12 0A 1E 8F 80 61 29 B2 06 61 56 88 32 87 73 15 AC E2 58 E0 9E 90 6A 05 A1 CD 5C 66 5C DB E5 86 06 B0 79 D6 -[2026-02-20T18:00:17.602925] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:17.651504] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cc 2e 07 00 00 00 69 23 00 00 -[2026-02-20T18:00:17.651584] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:17.651595] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:00:19.671242] LOG: [APP] App resumed from background -[2026-02-20T18:00:21.038729] LOG: [GPS SERVICE] Position stream fired: lat=47.33779, lon=-122.22648, accuracy=4.0m -[2026-02-20T18:00:22.573991] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:00:22.574081] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:00:22.602900] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:22.668943] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2e 07 00 00 00 69 23 00 00 -[2026-02-20T18:00:22.668991] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:22.669] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:22.759162] LOG: [CONN] Frame received (99 bytes): 88 2f b4 15 0b c7 43 fe 7b df b8 4e 1f 7e 2a dd 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 66 30 f2 77 62 5b -[2026-02-20T18:00:22.759317] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:22.759350] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:22.759447] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0B C7 43 FE 7B DF B8 4E 1F 7E 2A DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B -[2026-02-20T18:00:22.759471] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:22.759482] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:00:22.759510] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xdd, SNR=11.75, RSSI=-76, payload=83 bytes -[2026-02-20T18:00:22.759525] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:00:22.759536] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:22.759552] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:22.759666] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:22.759682] LOG: [RX FILTER] Raw packet (96 bytes): 15 0B C7 43 FE 7B DF B8 4E 1F 7E 2A DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B -[2026-02-20T18:00:22.759704] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 11.75 -[2026-02-20T18:00:22.759726] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) -[2026-02-20T18:00:22.759739] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:22.759749] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:00:22.759768] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:00:22.759781] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:00:22.759796] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:00:22.759908] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:00:22.760119] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40742, -122.51648 [..." -[2026-02-20T18:00:22.760144] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:00:22.760160] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:00:22.760192] LOG: [RX LOG] Packet heard via last hop: DD, SNR=11.75, path_length=11 -[2026-02-20T18:00:22.760204] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:00:22.760220] LOG: [RX BATCH] First observation for repeater DD: SNR=11.75 -[2026-02-20T18:00:22.760242] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:00:22.760261] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:00:22.760286] LOG: [APP] Immediate RX observation: repeater=DD, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:22.760306] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:00:22.760332] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.33779,-122.22648 (batch tracking: 1 repeaters, rxCount: 1) -[2026-02-20T18:00:22.760354] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:00:22.760378] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:22.760827] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:00:22.760840] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:00:22.760857] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:00:24.033582] LOG: [CONN] Frame received (100 bytes): 88 2f cb 15 0c c7 43 fe 7b df b8 4e 1f 7e 2a dd cc 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 66 30 f2 77 62 5b -[2026-02-20T18:00:24.033764] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:24.033797] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:24.033893] LOG: [RX PARSE] RAW Packet (97 bytes): 15 0C C7 43 FE 7B DF B8 4E 1F 7E 2A DD CC 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B -[2026-02-20T18:00:24.033914] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:24.033930] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:00:24.033957] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xc7, lastHop=0xcc, SNR=11.75, RSSI=-53, payload=83 bytes -[2026-02-20T18:00:24.033976] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:00:24.033990] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:24.033999] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:24.034091] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:24.034105] LOG: [RX FILTER] Raw packet (97 bytes): 15 0C C7 43 FE 7B DF B8 4E 1F 7E 2A DD CC 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 66 30 F2 77 62 5B -[2026-02-20T18:00:24.034131] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 -[2026-02-20T18:00:24.034145] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) -[2026-02-20T18:00:24.034163] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:24.034174] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:00:24.034185] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:00:24.034202] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:00:24.034213] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:00:24.034322] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:00:24.034557] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40742, -122.51648 [..." -[2026-02-20T18:00:24.034585] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:00:24.034595] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:00:24.034653] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=12 -[2026-02-20T18:00:24.034669] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:00:24.034688] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 -[2026-02-20T18:00:24.034705] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:00:24.034732] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:00:24.034753] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:24.034781] LOG: [APP] Current batch tracking: 1 repeaters: {DD} -[2026-02-20T18:00:24.034801] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.33779,-122.22648 (batch tracking: 2 repeaters, rxCount: 2) -[2026-02-20T18:00:24.034827] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:00:24.034848] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:27.602828] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:00:27.602947] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:27.672044] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:00:27.672123] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:00:27.672132] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:00:27.672142] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:00:27.736416] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 2f 07 00 00 00 6a 23 00 00 -[2026-02-20T18:00:27.736520] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:27.736532] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:28.650574] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:00:28.650708] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:00:28.650723] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:00:28.650763] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:00:28.650801] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.33779, -122.22648 [0.3w]" -[2026-02-20T18:00:28.650814] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:00:28.650821] LOG: [TX LOG] Payload: "@[MapperBot] 47.33779, -122.22648 [0.3w]" -[2026-02-20T18:00:28.650832] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:00:28.650846] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:00:28.650857] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:00:28.650865] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:00:28.650885] LOG: [CONN] Sending ping: @[MapperBot] 47.33779, -122.22648 [0.3w] -[2026-02-20T18:00:28.694272] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:00:28.694370] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:00:28.694386] LOG: [CONN] Received OK response -[2026-02-20T18:00:30.149716] LOG: [CONN] Frame received (73 bytes): 88 31 c8 15 01 cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:00:30.149819] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:30.149840] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:30.149875] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:00:30.149885] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:30.149892] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:00:30.149908] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=67 bytes -[2026-02-20T18:00:30.149915] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:00:30.149924] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:00:30.149931] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-56 -[2026-02-20T18:00:30.149939] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:00:30.149944] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:00:30.149951] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:30.149957] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:30.149964] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:00:31.040357] LOG: [GPS SERVICE] Position stream fired: lat=47.33820, lon=-122.22656, accuracy=4.1m -[2026-02-20T18:00:31.040434] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:00:31.040452] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger -[2026-02-20T18:00:31.040471] LOG: [RX BATCH] Distance check for repeater DD: 45.70m from first observation (threshold=25m) -[2026-02-20T18:00:31.040474] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:00:31.040480] LOG: [RX BATCH] Distance check for repeater CC: 45.70m from first observation (threshold=25m) -[2026-02-20T18:00:31.040482] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:00:31.040485] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:00:31.040490] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:00:31.040495] LOG: [RX BATCH] Posting repeater DD: snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:31.040497] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:00:31.040503] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:31.040508] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 11.75 <= pin 11.75 -[2026-02-20T18:00:31.040514] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 -[2026-02-20T18:00:31.040518] LOG: [APP] Added RX log entry: repeater=DD, snr=11.75, pathLen=11 -[2026-02-20T18:00:31.040531] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:00:31.040547] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:00:31.040550] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:00:31.040553] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:00:31.040556] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:31.040560] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:00:31.040562] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.33779,-122.22648 -[2026-02-20T18:00:31.040566] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 -[2026-02-20T18:00:31.040570] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:00:31.040572] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=12 -[2026-02-20T18:00:31.040603] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:00:31.040607] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement -[2026-02-20T18:00:31.456699] LOG: [CONN] Frame received (74 bytes): 88 2b a4 15 02 cc dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:00:31.456755] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:31.456799] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:31.456868] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 CC DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:00:31.456890] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:31.456901] LOG: [RX PARSE] Path length offset: 1, Path length: 2 -[2026-02-20T18:00:31.456930] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0xcc, lastHop=0xdd, SNR=10.75, RSSI=-92, payload=67 bytes -[2026-02-20T18:00:31.456951] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 -[2026-02-20T18:00:31.456961] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:00:31.456978] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-92 -[2026-02-20T18:00:31.456988] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:00:31.457] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd -[2026-02-20T18:00:31.457015] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:00:31.457028] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:00:31.457039] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:00:31.457056] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:00:31.457069] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:00:31.457164] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:00:31.457298] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... -[2026-02-20T18:00:31.457318] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.33779, -122.22648 [0.3w]" (47 chars) -[2026-02-20T18:00:31.457331] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.33779, -122.22648 [0.3w]" (40 chars) -[2026-02-20T18:00:31.457344] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! -[2026-02-20T18:00:31.457366] LOG: [PING] Repeater echo accepted: first_hop=dd, SNR=null, full_path_length=2 (CARpeater stripped) -[2026-02-20T18:00:31.457379] LOG: [PING] Adding new repeater echo: path=dd, SNR=null, RSSI=null -[2026-02-20T18:00:31.457391] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) -[2026-02-20T18:00:31.457398] LOG: [PING] onEchoReceived callback fired: dd, SNR=null, RSSI=null, isNew=true -[2026-02-20T18:00:31.457409] LOG: [PING] Real-time: Added new repeater dd (SNR: null) - total: 1 -[2026-02-20T18:00:31.457414] LOG: [PING] Calling onEchoReceived callback (callback=SET) -[2026-02-20T18:00:31.457419] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== -[2026-02-20T18:00:31.457427] LOG: [APP] Real-time echo: dd (SNR: null, isNew: true) -[2026-02-20T18:00:31.457431] LOG: [APP] TxLogEntries count: 2 -[2026-02-20T18:00:31.457458] LOG: [APP] Updated TxLogEntry with 1 events (real-time) -[2026-02-20T18:00:31.457465] LOG: [APP] Calling notifyListeners() to update UI -[2026-02-20T18:00:31.457472] LOG: [APP] notifyListeners() completed -[2026-02-20T18:00:31.457476] LOG: [PING] onEchoReceived callback completed -[2026-02-20T18:00:31.457483] LOG: [TX LOG] onEchoReceived callback invoked successfully -[2026-02-20T18:00:31.457489] LOG: [TX LOG] ✅ Echo tracked successfully -[2026-02-20T18:00:31.457558] LOG: [UNIFIED RX] Packet was TX echo, done -[2026-02-20T18:00:31.696341] LOG: [PING] Ping sent successfully -[2026-02-20T18:00:32.280470] LOG: [CONN] Frame received (100 bytes): 88 1f a5 15 12 c7 43 fe 7b f5 17 2b 75 20 20 20 20 20 20 20 75 7e dd 81 70 02 82 81 19 34 84 be 49 d0 85 0e 9c 19 e7 23 3a 54 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb e6 0f 63 a0 41 f0 5c 32 dc 6a b4 ec be 4c 5a 2a 95 06 aa 7b 4d 03 07 66 11 e3 -[2026-02-20T18:00:32.280599] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:32.280635] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:32.280701] LOG: [RX PARSE] RAW Packet (97 bytes): 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 -[2026-02-20T18:00:32.280720] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:32.280732] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:00:32.280758] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xc7, lastHop=0xdd, SNR=7.75, RSSI=-91, payload=77 bytes -[2026-02-20T18:00:32.280768] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T18:00:32.280781] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:00:32.280791] LOG: [TX LOG] Processing rx_log entry: SNR=7.75, RSSI=-91 -[2026-02-20T18:00:32.280802] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:00:32.280813] LOG: [TX LOG] ✓ RSSI OK (-91 < -30) -[2026-02-20T18:00:32.280822] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:00:32.280835] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:00:32.280843] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:00:32.280853] LOG: [CRYPTO] Decrypting message (74 bytes) -[2026-02-20T18:00:32.281008] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:32.281037] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:32.281051] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:32.281063] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:32.281128] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:32.281137] LOG: [RX FILTER] Raw packet (97 bytes): 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 -[2026-02-20T18:00:32.281156] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 7.75 -[2026-02-20T18:00:32.281174] LOG: [RX FILTER] ✓ RSSI OK (-91 < -30) -[2026-02-20T18:00:32.281182] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:32.281190] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:00:32.281201] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:00:32.281212] LOG: [RX FILTER] Encrypted message: 74 bytes -[2026-02-20T18:00:32.281219] LOG: [CRYPTO] Decrypting message (74 bytes) -[2026-02-20T18:00:32.281318] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:32.281354] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:32.281455] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) - - -[2026-02-20T18:00:32.281541] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:00:32.281551] LOG: [RX LOG] Dropped packet hex: 15 12 C7 43 FE 7B F5 17 2B 75 20 20 20 20 20 20 20 75 7E DD 81 70 02 82 81 19 34 84 BE 49 D0 85 0E 9C 19 E7 23 3A 54 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB E6 0F 63 A0 41 F0 5C 32 DC 6A B4 EC BE 4C 5A 2A 95 06 AA 7B 4D 03 07 66 11 E3 -[2026-02-20T18:00:32.604726] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:32.778500] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff a5 1f 08 00 00 00 6b 23 00 00 -[2026-02-20T18:00:32.778699] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:32.778722] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:00:33.651677] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) -[2026-02-20T18:00:33.651811] LOG: [TX LOG] Final: dd -> SNR=null, seen=1x -[2026-02-20T18:00:36.061143] LOG: [GPS SERVICE] Position stream fired: lat=47.33870, lon=-122.22656, accuracy=4.0m -[2026-02-20T18:00:36.698769] LOG: [PING] RX listening window ended -[2026-02-20T18:00:36.698855] LOG: [PING] TxTracker collected 1 repeater echoes -[2026-02-20T18:00:36.698886] LOG: [PING] Heard repeater: dd, SNR=null -[2026-02-20T18:00:36.699224] LOG: [GRAPH] Recorded txSuccess event at -120dBm with 1 repeater(s) -[2026-02-20T18:00:36.699289] LOG: [PING] Queued TX entry with heard_repeats: dd(null) -[2026-02-20T18:00:36.699302] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:00:36.699322] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:00:36.699349] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:00:36.699375] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:00:36.705932] LOG: [API QUEUE] TX enqueued: dd(null) (queue size: 1) -[2026-02-20T18:00:37.574178] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:00:37.574358] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:00:37.574367] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:00:37.574376] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:00:37.576167] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue -[2026-02-20T18:00:37.602882] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:37.781496] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff a5 1f 08 00 00 00 6b 23 00 00 -[2026-02-20T18:00:37.781585] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:37.781600] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:38.388030] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:00:38.388090] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:00:38.388108] LOG: [API] Response (200) in 0.81s: {"success":true,"expires_at":1771639538} -[2026-02-20T18:00:38.388122] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:00:38.388139] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:00:38.388655] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:00:38.388674] LOG: [APP] Upload success: +2 items (total: 3) -[2026-02-20T18:00:41.049752] LOG: [GPS SERVICE] Position stream fired: lat=47.33923, lon=-122.22654, accuracy=4.1m -[2026-02-20T18:00:41.719301] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:00:41.719349] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:00:41.719356] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:00:41.985767] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:00:41.985850] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:00:41.985872] LOG: [API] Response (200) in 0.27s: {"success":true,"expires_at":1771639541} -[2026-02-20T18:00:41.985889] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:00:41.985907] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:00:41.986771] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:00:41.986788] LOG: [APP] Upload success: +1 items (total: 4) -[2026-02-20T18:00:42.601774] LOG: [CONN] Frame received (139 bytes): 88 2a 9c 11 09 30 1c 26 ca ab 86 7a 7e dd ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 51 8b 47 66 4e a0 13 6f e6 9b 99 d9 cb e4 c1 6f 27 0a 6f 58 63 0c 10 eb c0 88 0d 1c df 1a d6 d0 9b 3a 74 d7 4b 5d cb 0c a9 df cb ca 02 22 bd a6 cc 54 76 be ed 3b 72 09 b0 ef 8d 80 01 e9 57 65 d4 25 ce 07 92 4c d0 ef 02 28 f5 a8 f8 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 -[2026-02-20T18:00:42.601931] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:42.602035] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:42.602155] LOG: [RX PARSE] RAW Packet (136 bytes): 11 09 30 1C 26 CA AB 86 7A 7E DD CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 -[2026-02-20T18:00:42.602182] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:00:42.602193] LOG: [RX PARSE] Path length offset: 1, Path length: 9 -[2026-02-20T18:00:42.602230] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=9, firstHop=0x30, lastHop=0xdd, SNR=10.5, RSSI=-100, payload=125 bytes -[2026-02-20T18:00:42.602244] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=9 -[2026-02-20T18:00:42.602260] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:42.602269] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:42.602383] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:42.602395] LOG: [RX FILTER] Raw packet (136 bytes): 11 09 30 1C 26 CA AB 86 7A 7E DD CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 -[2026-02-20T18:00:42.602422] LOG: [RX FILTER] Header: 0x11 | PathLength: 9 | SNR: 10.5 -[2026-02-20T18:00:42.602436] LOG: [RX FILTER] ✓ RSSI OK (-100 < -30) -[2026-02-20T18:00:42.602453] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:00:42.602464] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:00:42.602473] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:00:42.602669] LOG: [RX FILTER] ADVERT name extracted: "Salish//Seaforth" (16 chars) -[2026-02-20T18:00:42.602688] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:00:42.602715] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Salish//Seaforth") -[2026-02-20T18:00:42.602738] LOG: [RX LOG] Packet heard via last hop: DD, SNR=10.5, path_length=9 -[2026-02-20T18:00:42.602754] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:00:42.602772] LOG: [RX BATCH] First observation for repeater DD: SNR=10.5 -[2026-02-20T18:00:42.602796] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:00:42.602816] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:00:42.602837] LOG: [APP] Immediate RX observation: repeater=DD, snr=10.5, location=47.33923,-122.22654 -[2026-02-20T18:00:42.602861] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:00:42.602881] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.33923,-122.22654 (batch tracking: 1 repeaters, rxCount: 3) -[2026-02-20T18:00:42.602908] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:00:42.602929] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=10.5, location=47.33923,-122.22654 -[2026-02-20T18:00:42.603476] LOG: [CONN] Frame received (148 bytes): 8a ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 51 8b 47 66 4c d0 ef 02 28 f5 a8 f8 c9 11 99 69 -[2026-02-20T18:00:42.603506] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:00:42.603524] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:00:42.603725] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:42.642486] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 9c 2a 08 00 00 00 6b 23 00 00 -[2026-02-20T18:00:42.642607] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:42.642620] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:43.682908] LOG: [CONN] Frame received (140 bytes): 88 32 c8 11 0a 30 1c 26 ca ab 86 7a 7e dd cc ca 8e fa 39 b0 1c 29 6c de 4d 5b 82 25 0d e5 3f a4 a0 14 d9 11 b7 99 f1 89 a6 dc 53 8c 00 c9 7a 51 8b 47 66 4e a0 13 6f e6 9b 99 d9 cb e4 c1 6f 27 0a 6f 58 63 0c 10 eb c0 88 0d 1c df 1a d6 d0 9b 3a 74 d7 4b 5d cb 0c a9 df cb ca 02 22 bd a6 cc 54 76 be ed 3b 72 09 b0 ef 8d 80 01 e9 57 65 d4 25 ce 07 92 4c d0 ef 02 28 f5 a8 f8 53 61 6c 69 73 68 2f 2f 53 65 61 66 6f 72 74 68 -[2026-02-20T18:00:43.683093] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:43.683131] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:43.683252] LOG: [RX PARSE] RAW Packet (137 bytes): 11 0A 30 1C 26 CA AB 86 7A 7E DD CC CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 -[2026-02-20T18:00:43.683279] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:00:43.683295] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:00:43.683327] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=10, firstHop=0x30, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=125 bytes -[2026-02-20T18:00:43.683347] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=10 -[2026-02-20T18:00:43.683360] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:43.683369] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:43.683497] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:43.683510] LOG: [RX FILTER] Raw packet (137 bytes): 11 0A 30 1C 26 CA AB 86 7A 7E DD CC CA 8E FA 39 B0 1C 29 6C DE 4D 5B 82 25 0D E5 3F A4 A0 14 D9 11 B7 99 F1 89 A6 DC 53 8C 00 C9 7A 51 8B 47 66 4E A0 13 6F E6 9B 99 D9 CB E4 C1 6F 27 0A 6F 58 63 0C 10 EB C0 88 0D 1C DF 1A D6 D0 9B 3A 74 D7 4B 5D CB 0C A9 DF CB CA 02 22 BD A6 CC 54 76 BE ED 3B 72 09 B0 EF 8D 80 01 E9 57 65 D4 25 CE 07 92 4C D0 EF 02 28 F5 A8 F8 53 61 6C 69 73 68 2F 2F 53 65 61 66 6F 72 74 68 -[2026-02-20T18:00:43.683537] LOG: [RX FILTER] Header: 0x11 | PathLength: 10 | SNR: 12.5 -[2026-02-20T18:00:43.683555] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:00:43.683567] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:00:43.683577] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:00:43.683591] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:00:43.683718] LOG: [RX FILTER] ADVERT name extracted: "Salish//Seaforth" (16 chars) -[2026-02-20T18:00:43.683737] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:00:43.683756] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Salish//Seaforth") -[2026-02-20T18:00:43.683782] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=10 -[2026-02-20T18:00:43.683793] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:00:43.683809] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:00:43.683832] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:00:43.683858] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:00:43.683882] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.33923,-122.22654 -[2026-02-20T18:00:43.683902] LOG: [APP] Current batch tracking: 1 repeaters: {DD} -[2026-02-20T18:00:43.683927] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.33923,-122.22654 (batch tracking: 2 repeaters, rxCount: 4) -[2026-02-20T18:00:43.683948] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:00:43.683972] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.33923,-122.22654 -[2026-02-20T18:00:46.011542] LOG: [GPS SERVICE] Position stream fired: lat=47.33979, lon=-122.22652, accuracy=3.8m -[2026-02-20T18:00:46.011635] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger -[2026-02-20T18:00:46.011647] LOG: [RX BATCH] Distance check for repeater DD: 61.92m from first observation (threshold=25m) -[2026-02-20T18:00:46.011651] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:00:46.011655] LOG: [RX BATCH] Distance check for repeater CC: 61.92m from first observation (threshold=25m) -[2026-02-20T18:00:46.011659] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:00:46.011662] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:00:46.011668] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:00:46.011676] LOG: [RX BATCH] Posting repeater DD: snr=10.5, location=47.33923,-122.22654 -[2026-02-20T18:00:46.011679] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:00:46.011685] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=10.5, location=47.33923,-122.22654 -[2026-02-20T18:00:46.011690] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 10.50 <= pin 10.50 -[2026-02-20T18:00:46.011698] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 -[2026-02-20T18:00:46.011702] LOG: [APP] Added RX log entry: repeater=DD, snr=10.5, pathLen=9 -[2026-02-20T18:00:46.011720] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:00:46.011722] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:00:46.011726] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:00:46.011729] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.33923,-122.22654 -[2026-02-20T18:00:46.011731] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:00:46.011735] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.33923,-122.22654 -[2026-02-20T18:00:46.011738] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:00:46.011743] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:00:46.011747] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=10 -[2026-02-20T18:00:46.011754] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:00:46.011757] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement -[2026-02-20T18:00:46.987935] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:00:47.070320] LOG: [CONN] Frame received (84 bytes): 88 13 98 15 10 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 53 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee -[2026-02-20T18:00:47.070431] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:47.070460] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:47.070659] LOG: [RX PARSE] RAW Packet (81 bytes): 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:47.070671] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:47.070676] LOG: [RX PARSE] Path length offset: 1, Path length: 16 -[2026-02-20T18:00:47.070697] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=16, firstHop=0xcc, lastHop=0xdd, SNR=4.75, RSSI=-104, payload=63 bytes -[2026-02-20T18:00:47.070704] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=16 -[2026-02-20T18:00:47.070714] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:47.070719] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:47.070727] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:00:47.070758] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:47.070766] LOG: [RX FILTER] Raw packet (81 bytes): 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:47.070777] LOG: [RX FILTER] Header: 0x15 | PathLength: 16 | SNR: 4.75 -[2026-02-20T18:00:47.070782] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:00:47.070787] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:47.070796] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:00:47.070802] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:00:47.070808] LOG: [RX FILTER] Encrypted message: 60 bytes -[2026-02-20T18:00:47.070815] LOG: [CRYPTO] Decrypting message (60 bytes) -[2026-02-20T18:00:47.070908] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:47.070934] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:47.071059] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:00:47.071118] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:00:47.071123] LOG: [RX LOG] Dropped packet hex: 15 10 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:47.602826] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:47.720687] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 98 13 08 00 00 00 6c 23 00 00 -[2026-02-20T18:00:47.720736] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:47.720748] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:48.581683] LOG: [CONN] Frame received (85 bytes): 88 32 c9 15 11 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 53 7e dd cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab 22 4c ee a0 51 86 19 55 94 25 e0 39 e7 92 a9 03 64 ee -[2026-02-20T18:00:48.581797] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:00:48.581829] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:00:48.581876] LOG: [RX PARSE] RAW Packet (82 bytes): 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:48.581889] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:00:48.581899] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T18:00:48.581915] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-55, payload=63 bytes -[2026-02-20T18:00:48.581926] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T18:00:48.581934] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:00:48.581940] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:00:48.581951] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:00:48.581994] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:00:48.582001] LOG: [RX FILTER] Raw packet (82 bytes): 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:48.582017] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 12.5 -[2026-02-20T18:00:48.582023] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:00:48.582033] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:00:48.582042] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:00:48.582050] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:00:48.582062] LOG: [RX FILTER] Encrypted message: 60 bytes -[2026-02-20T18:00:48.582072] LOG: [CRYPTO] Decrypting message (60 bytes) -[2026-02-20T18:00:48.582198] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:48.582233] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:00:48.582392] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:00:48.582468] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:00:48.582475] LOG: [RX LOG] Dropped packet hex: 15 11 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 53 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB 22 4C EE A0 51 86 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:00:51.009746] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22649, accuracy=3.8m -[2026-02-20T18:00:52.573857] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:00:52.574011] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:00:52.574028] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:00:52.577913] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue -[2026-02-20T18:00:52.602747] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:52.664682] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 -[2026-02-20T18:00:52.664815] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:52.664834] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:53.104790] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:00:53.104860] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:00:53.104873] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771639552} -[2026-02-20T18:00:53.104890] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:00:53.104905] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:00:53.105199] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:00:53.105212] LOG: [APP] Upload success: +1 items (total: 5) -[2026-02-20T18:00:56.016358] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22592, accuracy=3.8m -[2026-02-20T18:00:57.604878] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:00:57.604990] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:00:57.674493] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:00:57.674664] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:00:57.674690] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:00:57.674707] LOG: [CONN] Battery updated: 4080mV (90%) -[2026-02-20T18:00:57.733654] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 -[2026-02-20T18:00:57.733770] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:00:57.733795] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:00:58.105822] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:01:02.014764] LOG: [GPS SERVICE] Position stream fired: lat=47.34012, lon=-122.22478, accuracy=3.8m -[2026-02-20T18:01:02.014855] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:01:02.014919] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:01:02.603191] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:02.743786] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c9 32 08 00 00 00 6c 23 00 00 -[2026-02-20T18:01:02.743894] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:02.743907] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:04.634007] LOG: [CONN] Frame received (77 bytes): 88 2e a3 15 05 75 62 7e 48 dd bb 37 b4 11 87 48 fb 51 fd 9d bc 04 80 2e 73 37 92 eb d6 d4 7c 0e 2b 3c 59 c6 3a 55 95 9a 79 ee 1f 7f 2e 3e 04 da c9 26 0d c5 67 ad 7e 48 58 3e e6 e2 70 a0 01 80 40 37 78 73 42 75 d3 2b 7b ef 81 b1 52 -[2026-02-20T18:01:04.634169] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:04.634197] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:04.634272] LOG: [RX PARSE] RAW Packet (74 bytes): 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:04.634294] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:04.634305] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:01:04.634337] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x75, lastHop=0xdd, SNR=11.5, RSSI=-93, payload=67 bytes -[2026-02-20T18:01:04.634351] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T18:01:04.634367] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:04.634378] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:04.634445] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:04.634457] LOG: [RX FILTER] Raw packet (74 bytes): 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:04.634482] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 11.5 -[2026-02-20T18:01:04.634501] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) -[2026-02-20T18:01:04.634512] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:04.634564] LOG: [RX FILTER] Channel hash: 0xbb -[2026-02-20T18:01:04.634581] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xbb -[2026-02-20T18:01:04.634660] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:01:04.634672] LOG: [RX LOG] Dropped packet hex: 15 05 75 62 7E 48 DD BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:05.639186] LOG: [CONN] Frame received (78 bytes): 88 2e c8 15 06 75 62 7e 48 dd cc bb 37 b4 11 87 48 fb 51 fd 9d bc 04 80 2e 73 37 92 eb d6 d4 7c 0e 2b 3c 59 c6 3a 55 95 9a 79 ee 1f 7f 2e 3e 04 da c9 26 0d c5 67 ad 7e 48 58 3e e6 e2 70 a0 01 80 40 37 78 73 42 75 d3 2b 7b ef 81 b1 52 -[2026-02-20T18:01:05.639298] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:05.639320] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:05.639383] LOG: [RX PARSE] RAW Packet (75 bytes): 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:05.639400] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:05.639408] LOG: [RX PARSE] Path length offset: 1, Path length: 6 -[2026-02-20T18:01:05.639428] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=6, firstHop=0x75, lastHop=0xcc, SNR=11.5, RSSI=-56, payload=67 bytes -[2026-02-20T18:01:05.639439] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=6 -[2026-02-20T18:01:05.639450] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:05.639458] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:05.639515] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:05.639524] LOG: [RX FILTER] Raw packet (75 bytes): 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:05.639541] LOG: [RX FILTER] Header: 0x15 | PathLength: 6 | SNR: 11.5 -[2026-02-20T18:01:05.639552] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:01:05.639564] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:05.639573] LOG: [RX FILTER] Channel hash: 0xbb -[2026-02-20T18:01:05.639581] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xbb -[2026-02-20T18:01:05.639644] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:01:05.639653] LOG: [RX LOG] Dropped packet hex: 15 06 75 62 7E 48 DD CC BB 37 B4 11 87 48 FB 51 FD 9D BC 04 80 2E 73 37 92 EB D6 D4 7C 0E 2B 3C 59 C6 3A 55 95 9A 79 EE 1F 7F 2E 3E 04 DA C9 26 0D C5 67 AD 7E 48 58 3E E6 E2 70 A0 01 80 40 37 78 73 42 75 D3 2B 7B EF 81 B1 52 -[2026-02-20T18:01:06.701451] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:01:06.701508] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:01:06.701531] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:01:06.701567] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:01:06.701611] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34012, -122.22478 [0.3w]" -[2026-02-20T18:01:06.701623] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:01:06.701638] LOG: [TX LOG] Payload: "@[MapperBot] 47.34012, -122.22478 [0.3w]" -[2026-02-20T18:01:06.701650] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:01:06.701663] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:01:06.701719] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:01:06.701730] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:01:06.701754] LOG: [CONN] Sending ping: @[MapperBot] 47.34012, -122.22478 [0.3w] -[2026-02-20T18:01:06.881160] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:01:06.881213] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:01:06.881219] LOG: [CONN] Received OK response -[2026-02-20T18:01:07.573618] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:01:07.573730] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:01:07.573734] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:01:07.602900] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:07.693795] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c8 2e 08 00 00 00 6d 23 00 00 -[2026-02-20T18:01:07.693921] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:07.693945] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:01:08.105137] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:01:08.105210] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:01:08.105295] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771639567} -[2026-02-20T18:01:08.105314] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:01:08.105336] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:01:08.108701] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:01:08.108737] LOG: [APP] Upload success: +1 items (total: 6) -[2026-02-20T18:01:08.462751] LOG: [CONN] Frame received (86 bytes): 88 1b 98 15 0e 15 c6 24 a5 fe f7 f5 17 53 7e e8 9b 1b dd 11 42 70 b8 35 2b e7 0f 02 38 d6 c7 5a 35 91 a0 2a 46 dc b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 -[2026-02-20T18:01:08.462810] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:08.462822] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:08.462845] LOG: [RX PARSE] RAW Packet (83 bytes): 15 0E 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:08.462850] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:08.462855] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:01:08.462867] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x15, lastHop=0xdd, SNR=6.75, RSSI=-104, payload=67 bytes -[2026-02-20T18:01:08.462874] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:01:08.462877] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:08.462881] LOG: [TX LOG] Processing rx_log entry: SNR=6.75, RSSI=-104 -[2026-02-20T18:01:08.462885] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:08.462889] LOG: [TX LOG] ✓ RSSI OK (-104 < -30) -[2026-02-20T18:01:08.462894] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x11, expected=0x81 -[2026-02-20T18:01:08.462896] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:01:08.462900] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:08.462904] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:08.462922] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:08.462925] LOG: [RX FILTER] Raw packet (83 bytes): 15 0E 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:08.462931] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 6.75 -[2026-02-20T18:01:08.462935] LOG: [RX FILTER] ✓ RSSI OK (-104 < -30) -[2026-02-20T18:01:08.462938] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:08.462940] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:01:08.462944] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:01:08.462947] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:01:08.462950] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:01:08.462982] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:01:08.463034] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" -[2026-02-20T18:01:08.463043] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:01:08.463046] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:01:08.463056] LOG: [RX LOG] Packet heard via last hop: DD, SNR=6.75, path_length=14 -[2026-02-20T18:01:08.463058] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:01:08.463066] LOG: [RX BATCH] First observation for repeater DD: SNR=6.75 -[2026-02-20T18:01:08.463071] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:01:08.463078] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:01:08.463083] LOG: [APP] Immediate RX observation: repeater=DD, snr=6.75, location=47.34012,-122.22478 -[2026-02-20T18:01:08.463090] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:01:08.463096] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34012,-122.22478 (batch tracking: 1 repeaters, rxCount: 5) -[2026-02-20T18:01:08.463105] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) -[2026-02-20T18:01:08.463110] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=6.75, location=47.34012,-122.22478 -[2026-02-20T18:01:08.469709] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:01:08.469722] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:01:08.469726] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:01:08.470609] LOG: [GPS SERVICE] Position stream fired: lat=47.34015, lon=-122.22369, accuracy=3.8m -[2026-02-20T18:01:08.470640] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:01:08.470647] LOG: [RX BATCH] Distance check for repeater DD: 82.38m from first observation (threshold=25m) -[2026-02-20T18:01:08.470653] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:01:08.470655] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:01:08.470660] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:01:08.470665] LOG: [RX BATCH] Posting repeater DD: snr=6.75, location=47.34012,-122.22478 -[2026-02-20T18:01:08.470668] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:01:08.470673] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=6.75, location=47.34012,-122.22478 -[2026-02-20T18:01:08.470678] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 6.75 <= pin 6.75 -[2026-02-20T18:01:08.470705] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 -[2026-02-20T18:01:08.470709] LOG: [APP] Added RX log entry: repeater=DD, snr=6.75, pathLen=14 -[2026-02-20T18:01:08.470775] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:01:08.470780] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:01:09.019461] LOG: [CONN] Frame received (73 bytes): 88 30 c8 15 01 cc 81 1a 53 67 98 d2 97 e0 c6 b5 0d 2d d5 86 97 e5 ca 5f 28 be 2e b0 27 0e 34 2a 0f ab 24 f9 a7 90 e5 c0 06 e5 a7 4b ec bf 6f e8 d9 da 81 4e 4e 35 60 e4 45 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:01:09.019771] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:09.019844] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:09.019975] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1A 53 67 98 D2 97 E0 C6 B5 0D 2D D5 86 97 E5 CA 5F 28 BE 2E B0 27 0E 34 2A 0F AB 24 F9 A7 90 E5 C0 06 E5 A7 4B EC BF 6F E8 D9 DA 81 4E 4E 35 60 E4 45 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:01:09.019992] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:09.020010] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:01:09.020069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=67 bytes -[2026-02-20T18:01:09.020127] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:01:09.020134] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:09.020142] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-56 -[2026-02-20T18:01:09.020611] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:09.020614] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:01:09.020619] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:09.020622] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:09.020625] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:01:09.600486] LOG: [CONN] Frame received (90 bytes): 88 2b 9d 15 28 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab -[2026-02-20T18:01:09.600576] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:09.600593] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:09.600633] LOG: [RX PARSE] RAW Packet (87 bytes): 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:09.600644] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:09.600650] LOG: [RX PARSE] Path length offset: 1, Path length: 40 -[2026-02-20T18:01:09.600670] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=40, firstHop=0xcc, lastHop=0xdd, SNR=10.75, RSSI=-99, payload=45 bytes -[2026-02-20T18:01:09.600678] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=40 -[2026-02-20T18:01:09.600689] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:09.600695] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-99 -[2026-02-20T18:01:09.600700] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:09.600709] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd -[2026-02-20T18:01:09.600715] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:09.600723] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:01:09.600730] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:01:09.600735] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:01:09.600745] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:09.600837] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:09.600857] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:09.600865] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:09.600875] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:09.600882] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:01:09.600918] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:09.600926] LOG: [RX FILTER] Raw packet (87 bytes): 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:09.600937] LOG: [RX FILTER] Header: 0x15 | PathLength: 40 | SNR: 10.75 -[2026-02-20T18:01:09.600945] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:09.600951] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:09.600956] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:09.600966] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:09.600972] LOG: [RX FILTER] Encrypted message: 42 bytes -[2026-02-20T18:01:09.600979] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:09.601039] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:09.601096] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:09.601164] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) - - -[2026-02-20T18:01:09.601216] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:09.601222] LOG: [RX LOG] Dropped packet hex: 15 28 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:09.881967] LOG: [PING] Ping sent successfully -[2026-02-20T18:01:10.130730] LOG: [CONN] Frame received (87 bytes): 88 32 c7 15 0f 15 c6 24 a5 fe f7 f5 17 53 7e e8 9b 1b dd cc 11 42 70 b8 35 2b e7 0f 02 38 d6 c7 5a 35 91 a0 2a 46 dc b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 -[2026-02-20T18:01:10.130819] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:10.130837] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:10.130874] LOG: [RX PARSE] RAW Packet (84 bytes): 15 0F 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD CC 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:10.130882] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:10.130891] LOG: [RX PARSE] Path length offset: 1, Path length: 15 -[2026-02-20T18:01:10.130910] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0x15, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes -[2026-02-20T18:01:10.130919] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 -[2026-02-20T18:01:10.130925] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:10.130930] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-57 -[2026-02-20T18:01:10.130937] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:10.130944] LOG: [TX LOG] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:01:10.130949] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x11, expected=0x81 -[2026-02-20T18:01:10.130956] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:01:10.130962] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:10.130969] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:10.131006] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:10.131012] LOG: [RX FILTER] Raw packet (84 bytes): 15 0F 15 C6 24 A5 FE F7 F5 17 53 7E E8 9B 1B DD CC 11 42 70 B8 35 2B E7 0F 02 38 D6 C7 5A 35 91 A0 2A 46 DC B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:10.131023] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 12.5 -[2026-02-20T18:01:10.131030] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:01:10.131037] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:10.131044] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:01:10.131049] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:01:10.131057] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:01:10.131062] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:01:10.131105] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:01:10.131201] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" -[2026-02-20T18:01:10.131215] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:01:10.131220] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:01:10.131236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=15 -[2026-02-20T18:01:10.131241] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:01:10.131251] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:01:10.131259] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:01:10.131306] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:01:10.131330] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.34015,-122.22369 -[2026-02-20T18:01:10.131343] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:01:10.131357] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34015,-122.22369 (batch tracking: 1 repeaters, rxCount: 6) -[2026-02-20T18:01:10.131370] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) -[2026-02-20T18:01:10.131397] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.34015,-122.22369 -[2026-02-20T18:01:11.518346] LOG: [CONN] Frame received (91 bytes): 88 32 c8 15 29 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e dd cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a ab -[2026-02-20T18:01:11.518363] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:11.518372] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:11.518387] LOG: [RX PARSE] RAW Packet (88 bytes): 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:11.518390] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:11.518392] LOG: [RX PARSE] Path length offset: 1, Path length: 41 -[2026-02-20T18:01:11.518397] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=41, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=45 bytes -[2026-02-20T18:01:11.518400] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=41 -[2026-02-20T18:01:11.518401] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:11.518403] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 -[2026-02-20T18:01:11.518405] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:11.518407] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater dd -[2026-02-20T18:01:11.518409] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:11.518412] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:01:11.518413] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:01:11.518415] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:01:11.518418] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:11.518464] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:11.518470] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:11.518571] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:11.518575] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:11.518578] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:01:11.518602] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:11.518606] LOG: [RX FILTER] Raw packet (88 bytes): 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:11.518612] LOG: [RX FILTER] Header: 0x15 | PathLength: 41 | SNR: 12.5 -[2026-02-20T18:01:11.518614] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:11.518617] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:11.518621] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:11.518625] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:11.518627] LOG: [RX FILTER] Encrypted message: 42 bytes -[2026-02-20T18:01:11.518632] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:11.518668] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:11.518681] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:11.518767] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) - - -[2026-02-20T18:01:11.518795] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:11.518798] LOG: [RX LOG] Dropped packet hex: 15 29 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A AB -[2026-02-20T18:01:11.702655] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:01:12.602831] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:12.794405] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 08 00 00 00 6e 23 00 00 -[2026-02-20T18:01:12.794573] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:12.794593] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:13.109698] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:01:14.882773] LOG: [PING] RX listening window ended -[2026-02-20T18:01:14.882887] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:01:14.882910] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:01:14.882966] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:01:14.882979] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:01:14.882989] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:01:14.883006] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:01:14.883022] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:01:14.883400] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:01:17.604] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:17.656099] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 08 00 00 00 6e 23 00 00 -[2026-02-20T18:01:17.656210] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:17.656228] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:17.898544] LOG: [CONN] Frame received (129 bytes): 88 27 98 15 09 bf 1c 0a 1b ab 5a 7a 7e dd ef 42 dd f2 2a 93 9a 4d 81 3e b1 54 5d cf 1e 94 49 f5 65 26 e4 58 5c 3d 13 b1 70 a9 f4 81 24 b1 86 76 b8 79 78 86 2f a1 21 fa 20 ea 2a ee 14 37 66 c9 31 cb 33 b9 cf 85 9a 21 84 97 c6 f9 c2 80 5f fa df 6b de aa ee 18 df 39 30 09 92 11 9d 17 ff ce f9 c8 03 7d 0e 9c 72 ea fc c7 ac 79 2c 2b 65 b0 67 90 a4 90 7a 9f 69 48 fa c0 a9 7f 5b f3 03 ff 05 -[2026-02-20T18:01:17.898656] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:17.898683] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:17.898733] LOG: [RX PARSE] RAW Packet (126 bytes): 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 -[2026-02-20T18:01:17.898742] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:17.898752] LOG: [RX PARSE] Path length offset: 1, Path length: 9 -[2026-02-20T18:01:17.898766] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0xbf, lastHop=0xdd, SNR=9.75, RSSI=-104, payload=115 bytes -[2026-02-20T18:01:17.898774] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 -[2026-02-20T18:01:17.898779] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:17.898783] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:17.898827] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:17.898835] LOG: [RX FILTER] Raw packet (126 bytes): 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 -[2026-02-20T18:01:17.898846] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 9.75 -[2026-02-20T18:01:17.898853] LOG: [RX FILTER] ✓ RSSI OK (-104 < -30) -[2026-02-20T18:01:17.898857] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:17.898884] LOG: [RX FILTER] Channel hash: 0xef -[2026-02-20T18:01:17.898890] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xef -[2026-02-20T18:01:17.898939] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:01:17.898947] LOG: [RX LOG] Dropped packet hex: 15 09 BF 1C 0A 1B AB 5A 7A 7E DD EF 42 DD F2 2A 93 9A 4D 81 3E B1 54 5D CF 1E 94 49 F5 65 26 E4 58 5C 3D 13 B1 70 A9 F4 81 24 B1 86 76 B8 79 78 86 2F A1 21 FA 20 EA 2A EE 14 37 66 C9 31 CB 33 B9 CF 85 9A 21 84 97 C6 F9 C2 80 5F FA DF 6B DE AA EE 18 DF 39 30 09 92 11 9D 17 FF CE F9 C8 03 7D 0E 9C 72 EA FC C7 AC 79 2C 2B 65 B0 67 90 A4 90 7A 9F 69 48 FA C0 A9 7F 5B F3 03 FF 05 -[2026-02-20T18:01:18.014656] LOG: [GPS SERVICE] Position stream fired: lat=47.34017, lon=-122.22260, accuracy=3.8m -[2026-02-20T18:01:18.014724] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:01:18.014734] LOG: [RX BATCH] Distance check for repeater CC: 82.23m from first observation (threshold=25m) -[2026-02-20T18:01:18.014741] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:01:18.014744] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:01:18.014751] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:01:18.014756] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.34015,-122.22369 -[2026-02-20T18:01:18.014760] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:01:18.014766] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.34015,-122.22369 -[2026-02-20T18:01:18.014771] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:01:18.014778] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:01:18.014783] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=15 -[2026-02-20T18:01:18.014799] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:01:18.014803] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:01:19.885371] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:01:19.885618] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:01:19.885639] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:01:19.885652] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:01:19.886837] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue -[2026-02-20T18:01:20.383765] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:01:20.383817] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:01:20.383829] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771639580} -[2026-02-20T18:01:20.383841] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:01:20.383852] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:01:20.384524] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:01:20.384541] LOG: [APP] Upload success: +2 items (total: 8) -[2026-02-20T18:01:22.573756] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:01:22.573855] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:01:22.573876] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:01:22.605348] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:22.784777] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 98 27 08 00 00 00 6f 23 00 00 -[2026-02-20T18:01:22.784902] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:22.784926] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:01:22.831413] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:01:22.831490] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:01:22.831506] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771639582} -[2026-02-20T18:01:22.831564] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:01:22.831599] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:01:22.831978] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:01:22.831994] LOG: [APP] Upload success: +1 items (total: 9) -[2026-02-20T18:01:26.791819] LOG: [CONN] Frame received (107 bytes): 88 31 9e 15 39 cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e 5a 2d ab a4 61 c1 43 1c 89 0a 1b ab 5a a7 cf 7a 7e dd 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a a8 -[2026-02-20T18:01:26.791880] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:26.791924] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:26.792024] LOG: [RX PARSE] RAW Packet (104 bytes): 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:26.792049] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:26.792062] LOG: [RX PARSE] Path length offset: 1, Path length: 57 -[2026-02-20T18:01:26.792096] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=57, firstHop=0xcc, lastHop=0xdd, SNR=12.25, RSSI=-98, payload=45 bytes -[2026-02-20T18:01:26.792113] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=57 -[2026-02-20T18:01:26.792123] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:26.792139] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:26.792151] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:01:26.792238] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:26.792250] LOG: [RX FILTER] Raw packet (104 bytes): 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:26.792274] LOG: [RX FILTER] Header: 0x15 | PathLength: 57 | SNR: 12.25 -[2026-02-20T18:01:26.792284] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:26.792298] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:26.792310] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:26.792322] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:26.792338] LOG: [RX FILTER] Encrypted message: 42 bytes -[2026-02-20T18:01:26.792351] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:26.792516] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:26.792666] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:26.792906] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:26.793033] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:26.793051] LOG: [RX LOG] Dropped packet hex: 15 39 CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E DD 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:27.300453] LOG: [CONN] Frame received (108 bytes): 88 31 c5 15 3a cc dd 48 9b c7 7d 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e 5a 2d ab a4 61 c1 43 1c 89 0a 1b ab 5a a7 cf 7a 7e 9b cc 81 a1 c8 65 4b 6d 8a b2 28 83 2f f9 30 88 d4 8c ba 40 c6 a5 47 65 12 73 4e 90 0a 9d a2 9c d2 fb af c3 07 a3 70 73 17 47 e8 70 45 6a a8 -[2026-02-20T18:01:27.300582] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:27.300610] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:27.300680] LOG: [RX PARSE] RAW Packet (105 bytes): 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:27.300698] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:27.300707] LOG: [RX PARSE] Path length offset: 1, Path length: 58 -[2026-02-20T18:01:27.300729] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=58, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=45 bytes -[2026-02-20T18:01:27.300741] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=58 -[2026-02-20T18:01:27.300752] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:27.300762] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:27.300772] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DD -[2026-02-20T18:01:27.300846] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:27.300856] LOG: [RX FILTER] Raw packet (105 bytes): 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:27.300875] LOG: [RX FILTER] Header: 0x15 | PathLength: 58 | SNR: 12.25 -[2026-02-20T18:01:27.300882] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:01:27.300895] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:27.300904] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:27.300914] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:27.300927] LOG: [RX FILTER] Encrypted message: 42 bytes -[2026-02-20T18:01:27.300936] LOG: [CRYPTO] Decrypting message (42 bytes) -[2026-02-20T18:01:27.301073] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:27.301112] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:27.301405] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:27.301516] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:27.301529] LOG: [RX LOG] Dropped packet hex: 15 3A CC DD 48 9B C7 7D 17 53 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E 5A 2D AB A4 61 C1 43 1C 89 0A 1B AB 5A A7 CF 7A 7E 9B CC 81 A1 C8 65 4B 6D 8A B2 28 83 2F F9 30 88 D4 8C BA 40 C6 A5 47 65 12 73 4E 90 0A 9D A2 9C D2 FB AF C3 07 A3 70 73 17 47 E8 70 45 6A A8 -[2026-02-20T18:01:27.602898] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:01:27.603132] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:27.641986] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:01:27.642102] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:01:27.642125] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:01:27.642142] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:01:27.707990] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c5 31 08 00 00 00 70 23 00 00 -[2026-02-20T18:01:27.708111] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:27.708130] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:01:27.832713] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:01:32.603135] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:32.780026] LOG: [CONN] Frame received (91 bytes): 88 2d 9e 15 03 c7 7e dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f 80 80 49 -[2026-02-20T18:01:32.780232] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:32.780303] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:32.780433] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 C7 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 -[2026-02-20T18:01:32.780462] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:32.780474] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:01:32.780522] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xc7, lastHop=0xdd, SNR=11.25, RSSI=-98, payload=83 bytes -[2026-02-20T18:01:32.780548] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:01:32.780559] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:32.780574] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:32.780651] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:32.780663] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 C7 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 -[2026-02-20T18:01:32.780686] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 -[2026-02-20T18:01:32.780700] LOG: [RX FILTER] ✓ RSSI OK (-98 < -30) -[2026-02-20T18:01:32.780716] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:32.780727] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:32.780738] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:32.780755] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:01:32.780765] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:01:32.780866] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:01:32.781020] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40731, -122.50463 [..." -[2026-02-20T18:01:32.781050] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:01:32.781060] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:01:32.781090] LOG: [RX LOG] Packet heard via last hop: DD, SNR=11.25, path_length=3 -[2026-02-20T18:01:32.781107] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:01:32.781123] LOG: [RX BATCH] First observation for repeater DD: SNR=11.25 -[2026-02-20T18:01:32.781139] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:01:32.781162] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:01:32.781182] LOG: [APP] Immediate RX observation: repeater=DD, snr=11.25, location=47.34017,-122.22260 -[2026-02-20T18:01:32.781213] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:01:32.781233] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34017,-122.22260 (batch tracking: 1 repeaters, rxCount: 7) -[2026-02-20T18:01:32.781257] LOG: [GRAPH] Recorded rx event at -120dBm with 1 repeater(s) -[2026-02-20T18:01:32.781276] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=11.25, location=47.34017,-122.22260 -[2026-02-20T18:01:32.781744] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:01:32.781758] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:01:32.781768] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:01:32.802932] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 9e 2d 08 00 00 00 70 23 00 00 -[2026-02-20T18:01:32.802967] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:32.802976] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:34.084218] LOG: [CONN] Frame received (92 bytes): 88 30 c4 15 04 c7 7e 2a cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f 80 80 49 -[2026-02-20T18:01:34.084364] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:34.084393] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:34.084487] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 C7 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 -[2026-02-20T18:01:34.084505] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:34.084521] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:01:34.084579] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=83 bytes -[2026-02-20T18:01:34.084598] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:01:34.084611] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:34.084621] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:34.084702] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:34.084715] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 C7 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F 80 80 49 -[2026-02-20T18:01:34.084739] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 -[2026-02-20T18:01:34.084754] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:01:34.084769] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:34.084783] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:34.084794] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:34.084811] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:01:34.084824] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:01:34.084923] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:01:34.085104] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.40731, -122.50463 [..." -[2026-02-20T18:01:34.085133] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:01:34.085143] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:01:34.085173] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 -[2026-02-20T18:01:34.085184] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:01:34.085206] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 -[2026-02-20T18:01:34.085223] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:01:34.085246] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:01:34.085269] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.34017,-122.22260 -[2026-02-20T18:01:34.085306] LOG: [APP] Current batch tracking: 1 repeaters: {DD} -[2026-02-20T18:01:34.085326] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34017,-122.22260 (batch tracking: 2 repeaters, rxCount: 8) -[2026-02-20T18:01:34.085351] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:01:34.085372] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.34017,-122.22260 -[2026-02-20T18:01:37.574051] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:01:37.574147] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:01:37.602906] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:37.723152] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 08 00 00 00 70 23 00 00 -[2026-02-20T18:01:37.723299] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:37.723325] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:40.018568] LOG: [GPS SERVICE] Position stream fired: lat=47.34022, lon=-122.22241, accuracy=3.8m -[2026-02-20T18:01:40.018636] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:01:40.018652] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger -[2026-02-20T18:01:40.018666] LOG: [RX BATCH] Distance check for repeater DD: 14.97m from first observation (threshold=25m) -[2026-02-20T18:01:40.018669] LOG: [RX BATCH] Distance check for repeater CC: 14.97m from first observation (threshold=25m) -[2026-02-20T18:01:40.018687] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:01:42.358301] LOG: [CONN] Frame received (96 bytes): 88 2b 9c 15 0b c7 7e 75 20 20 20 53 7a 7e 2a dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f -[2026-02-20T18:01:42.358318] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:42.358330] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:42.358348] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.358353] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:42.358355] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:01:42.358364] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xdd, SNR=10.75, RSSI=-100, payload=80 bytes -[2026-02-20T18:01:42.358367] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:01:42.358369] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:42.358372] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:42.358388] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:42.358390] LOG: [RX FILTER] Raw packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.358394] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 10.75 -[2026-02-20T18:01:42.358399] LOG: [RX FILTER] ✓ RSSI OK (-100 < -30) -[2026-02-20T18:01:42.358413] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:42.358427] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:42.358446] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:42.358448] LOG: [RX FILTER] Encrypted message: 77 bytes -[2026-02-20T18:01:42.358450] LOG: [CRYPTO] Decrypting message (77 bytes) -[2026-02-20T18:01:42.358506] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:42.358598] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:42.358662] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:42.358689] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:42.358691] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 53 7A 7E 2A DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.602599] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:42.616969] LOG: [CONN] Frame received (96 bytes): 88 30 c5 15 0b c7 7e 75 20 20 20 53 7a 7e 2a cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd 5f -[2026-02-20T18:01:42.616999] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:42.617007] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:42.617023] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.617028] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:42.617031] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:01:42.617037] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=80 bytes -[2026-02-20T18:01:42.617041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:01:42.617044] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:42.617046] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:42.617060] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:42.617063] LOG: [RX FILTER] Raw packet (93 bytes): 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.617068] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.0 -[2026-02-20T18:01:42.617070] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:01:42.617073] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:42.617081] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:42.617084] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:42.617089] LOG: [RX FILTER] Encrypted message: 77 bytes -[2026-02-20T18:01:42.617091] LOG: [CRYPTO] Decrypting message (77 bytes) -[2026-02-20T18:01:42.617164] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:42.617178] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:42.617223] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:42.617250] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:42.617253] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 53 7A 7E 2A CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD 5F -[2026-02-20T18:01:42.643955] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c5 30 08 00 00 00 71 23 00 00 -[2026-02-20T18:01:42.643994] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:42.644001] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:01:43.378237] LOG: [CONN] Frame received (94 bytes): 88 1a 93 15 0a c7 7e 75 20 20 20 20 53 7e dd 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd -[2026-02-20T18:01:43.378296] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:43.378306] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:43.378325] LOG: [RX PARSE] RAW Packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:43.378329] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:43.378333] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:01:43.378345] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xc7, lastHop=0xdd, SNR=6.5, RSSI=-109, payload=79 bytes -[2026-02-20T18:01:43.378349] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:01:43.378353] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:43.378355] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:43.378371] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:43.378375] LOG: [RX FILTER] Raw packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:43.378381] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 6.5 -[2026-02-20T18:01:43.378385] LOG: [RX FILTER] ✓ RSSI OK (-109 < -30) -[2026-02-20T18:01:43.378387] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:43.378392] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:43.378394] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:43.378396] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:01:43.378402] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:01:43.378496] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:43.378512] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:43.378577] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:43.378604] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:43.378608] LOG: [RX LOG] Dropped packet hex: 15 0A C7 7E 75 20 20 20 20 53 7E DD 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:43.798062] LOG: [CONN] Frame received (94 bytes): 88 2f c6 15 0a c7 7e 75 20 20 20 20 53 7e cc 81 cd 9b 7c ad fe 21 b8 f7 7c 9a 76 15 ba 1a 68 47 89 55 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d6 5b b1 21 90 91 f1 20 28 07 04 b2 cd 51 52 62 8d 01 fa b3 5f 24 d9 65 e8 4c 3c fd -[2026-02-20T18:01:43.798111] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:43.798120] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:43.798135] LOG: [RX PARSE] RAW Packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:43.798140] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:43.798143] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:01:43.798153] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xc7, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=79 bytes -[2026-02-20T18:01:43.798156] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:01:43.798158] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:43.798160] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:43.798175] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:43.798179] LOG: [RX FILTER] Raw packet (91 bytes): 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:43.798184] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 11.75 -[2026-02-20T18:01:43.798189] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:01:43.798191] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:43.798194] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:01:43.798197] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:01:43.798200] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:01:43.798204] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:01:43.798264] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:43.798308] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:01:43.798363] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:01:43.798387] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:01:43.798393] LOG: [RX LOG] Dropped packet hex: 15 0A C7 7E 75 20 20 20 20 53 7E CC 81 CD 9B 7C AD FE 21 B8 F7 7C 9A 76 15 BA 1A 68 47 89 55 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D6 5B B1 21 90 91 F1 20 28 07 04 B2 CD 51 52 62 8D 01 FA B3 5F 24 D9 65 E8 4C 3C FD -[2026-02-20T18:01:44.884641] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:01:44.884791] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:01:44.884809] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:01:44.884857] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:01:44.884898] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34022, -122.22241 [0.3w]" -[2026-02-20T18:01:44.884915] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:01:44.884925] LOG: [TX LOG] Payload: "@[MapperBot] 47.34022, -122.22241 [0.3w]" -[2026-02-20T18:01:44.884938] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:01:44.884955] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:01:44.884968] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:01:44.884979] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:01:44.885005] LOG: [CONN] Sending ping: @[MapperBot] 47.34022, -122.22241 [0.3w] -[2026-02-20T18:01:45.011657] LOG: [GPS SERVICE] Position stream fired: lat=47.34061, lon=-122.22225, accuracy=3.8m -[2026-02-20T18:01:45.011744] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger -[2026-02-20T18:01:45.011755] LOG: [RX BATCH] Distance check for repeater DD: 55.21m from first observation (threshold=25m) -[2026-02-20T18:01:45.011759] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:01:45.011762] LOG: [RX BATCH] Distance check for repeater CC: 55.21m from first observation (threshold=25m) -[2026-02-20T18:01:45.011767] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:01:45.011769] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:01:45.011775] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:01:45.011782] LOG: [RX BATCH] Posting repeater DD: snr=11.25, location=47.34017,-122.22260 -[2026-02-20T18:01:45.011785] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:01:45.011790] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=11.25, location=47.34017,-122.22260 -[2026-02-20T18:01:45.011796] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 11.25 <= pin 11.25 -[2026-02-20T18:01:45.011802] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=1 -[2026-02-20T18:01:45.011807] LOG: [APP] Added RX log entry: repeater=DD, snr=11.25, pathLen=3 -[2026-02-20T18:01:45.011824] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:01:45.011826] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:01:45.011830] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:01:45.011834] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.34017,-122.22260 -[2026-02-20T18:01:45.011837] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:01:45.011841] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.34017,-122.22260 -[2026-02-20T18:01:45.011843] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 -[2026-02-20T18:01:45.011849] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:01:45.011852] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 -[2026-02-20T18:01:45.011858] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:01:45.011862] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement -[2026-02-20T18:01:45.040969] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:01:45.041009] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:01:45.041013] LOG: [CONN] Received OK response -[2026-02-20T18:01:46.680654] LOG: [CONN] Frame received (73 bytes): 88 12 8f 15 01 dd 81 e4 86 22 30 90 70 77 65 f7 af ee 40 53 b3 bc 00 a1 fd 5d b1 eb 1e 09 f1 fc cf d6 92 69 64 ae ea 10 45 8a 8e 97 ca be a2 72 bd ca f7 03 b0 66 b4 f7 dc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:01:46.680685] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:46.680705] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:46.680733] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 DD 81 E4 86 22 30 90 70 77 65 F7 AF EE 40 53 B3 BC 00 A1 FD 5D B1 EB 1E 09 F1 FC CF D6 92 69 64 AE EA 10 45 8A 8E 97 CA BE A2 72 BD CA F7 03 B0 66 B4 F7 DC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:01:46.680739] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:46.680745] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:01:46.680760] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xdd, lastHop=0xdd, SNR=4.5, RSSI=-113, payload=67 bytes -[2026-02-20T18:01:46.680768] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:01:46.680774] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:46.680778] LOG: [TX LOG] Processing rx_log entry: SNR=4.5, RSSI=-113 -[2026-02-20T18:01:46.680784] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:46.680791] LOG: [TX LOG] ✓ RSSI OK (-113 < -30) -[2026-02-20T18:01:46.680796] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:01:46.680805] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:01:46.680809] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:01:46.680815] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:01:46.680855] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:01:46.680944] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... -[2026-02-20T18:01:46.680954] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.34022, -122.22241 [0.3w]" (47 chars) -[2026-02-20T18:01:46.680959] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.34022, -122.22241 [0.3w]" (40 chars) -[2026-02-20T18:01:46.680965] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! -[2026-02-20T18:01:46.680972] LOG: [PING] Repeater echo accepted: first_hop=dd, SNR=4.5, full_path_length=1 -[2026-02-20T18:01:46.680979] LOG: [PING] Adding new repeater echo: path=dd, SNR=4.5, RSSI=-113 -[2026-02-20T18:01:46.680986] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) -[2026-02-20T18:01:46.680991] LOG: [PING] onEchoReceived callback fired: dd, SNR=4.5, RSSI=-113, isNew=true -[2026-02-20T18:01:46.680999] LOG: [PING] Real-time: Added new repeater dd (SNR: 4.5) - total: 1 -[2026-02-20T18:01:46.681003] LOG: [PING] Calling onEchoReceived callback (callback=SET) -[2026-02-20T18:01:46.681008] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== -[2026-02-20T18:01:46.681015] LOG: [APP] Real-time echo: dd (SNR: 4.5, isNew: true) -[2026-02-20T18:01:46.681020] LOG: [APP] TxLogEntries count: 4 -[2026-02-20T18:01:46.681027] LOG: [APP] Updated TxLogEntry with 1 events (real-time) -[2026-02-20T18:01:46.681031] LOG: [APP] Calling notifyListeners() to update UI -[2026-02-20T18:01:46.681037] LOG: [APP] notifyListeners() completed -[2026-02-20T18:01:46.681043] LOG: [PING] onEchoReceived callback completed -[2026-02-20T18:01:46.681048] LOG: [TX LOG] onEchoReceived callback invoked successfully -[2026-02-20T18:01:46.681052] LOG: [TX LOG] ✅ Echo tracked successfully -[2026-02-20T18:01:46.681110] LOG: [UNIFIED RX] Packet was TX echo, done -[2026-02-20T18:01:47.460560] LOG: [CONN] Frame received (73 bytes): 88 32 c6 15 01 cc 81 e4 86 22 30 90 70 77 65 f7 af ee 40 53 b3 bc 00 a1 fd 5d b1 eb 1e 09 f1 fc cf d6 92 69 64 ae ea 10 45 8a 8e 97 ca be a2 72 bd ca f7 03 b0 66 b4 f7 dc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:01:47.460728] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:47.460759] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:47.460833] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 E4 86 22 30 90 70 77 65 F7 AF EE 40 53 B3 BC 00 A1 FD 5D B1 EB 1E 09 F1 FC CF D6 92 69 64 AE EA 10 45 8A 8E 97 CA BE A2 72 BD CA F7 03 B0 66 B4 F7 DC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:01:47.460854] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:47.460864] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:01:47.460899] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes -[2026-02-20T18:01:47.460913] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:01:47.460927] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:01:47.460941] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 -[2026-02-20T18:01:47.460951] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:01:47.460965] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:01:47.460978] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:47.460987] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:47.461002] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:01:47.605992] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:47.656450] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 32 08 00 00 00 72 23 00 00 -[2026-02-20T18:01:47.656581] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:47.656607] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:01:48.042157] LOG: [PING] Ping sent successfully -[2026-02-20T18:01:49.886384] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) -[2026-02-20T18:01:49.886710] LOG: [TX LOG] Final: dd -> SNR=4.5, seen=1x -[2026-02-20T18:01:50.450298] LOG: [GPS SERVICE] Position stream fired: lat=47.34125, lon=-122.22220, accuracy=3.8m -[2026-02-20T18:01:52.573651] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:01:52.573749] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:01:52.573757] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:01:52.574910] LOG: [API QUEUE] Flushed 2 RX items from 2 repeaters to queue -[2026-02-20T18:01:52.602651] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:52.692253] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 32 08 00 00 00 72 23 00 00 -[2026-02-20T18:01:52.692331] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:52.692342] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:01:53.042914] LOG: [PING] RX listening window ended -[2026-02-20T18:01:53.043037] LOG: [PING] TxTracker collected 1 repeater echoes -[2026-02-20T18:01:53.043068] LOG: [PING] Heard repeater: dd, SNR=4.5 -[2026-02-20T18:01:53.043317] LOG: [GRAPH] Recorded txSuccess event at -119dBm with 1 repeater(s) -[2026-02-20T18:01:53.043377] LOG: [PING] Queued TX entry with heard_repeats: dd(4.50) -[2026-02-20T18:01:53.043388] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:01:53.043402] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:01:53.043449] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:01:53.043466] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:01:53.044205] LOG: [API QUEUE] TX enqueued: dd(4.50) (queue size: 3) -[2026-02-20T18:01:53.260980] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:01:53.261015] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:01:53.261023] LOG: [API] Response (200) in 0.69s: {"success":true,"expires_at":1771639613} -[2026-02-20T18:01:53.261030] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:01:53.261038] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:01:53.261239] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:01:53.261249] LOG: [APP] Upload success: +1 items (total: 10) -[2026-02-20T18:01:55.470302] LOG: [GPS SERVICE] Position stream fired: lat=47.34201, lon=-122.22225, accuracy=3.8m -[2026-02-20T18:01:57.437946] LOG: [CONN] Frame received (76 bytes): 88 0a 8e 15 04 15 ae 7e dd 11 89 be e5 da cc cb dd 57 18 90 85 61 6f 39 2c 8e ab 03 b3 79 ea e8 96 47 9d ab eb 7e 85 5e 22 1f 98 a8 08 9d 98 d6 43 f4 cd 2f 7a 00 dd 6e bd 82 09 2d 59 69 ee dc c8 6d ef a2 f8 6f a0 35 44 18 17 e4 -[2026-02-20T18:01:57.437994] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:01:57.438028] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:01:57.438074] LOG: [RX PARSE] RAW Packet (73 bytes): 15 04 15 AE 7E DD 11 89 BE E5 DA CC CB DD 57 18 90 85 61 6F 39 2C 8E AB 03 B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:57.438085] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:01:57.438096] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:01:57.438121] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xdd, SNR=2.5, RSSI=-114, payload=67 bytes -[2026-02-20T18:01:57.438134] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:01:57.438142] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:01:57.438148] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:01:57.438190] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:01:57.438200] LOG: [RX FILTER] Raw packet (73 bytes): 15 04 15 AE 7E DD 11 89 BE E5 DA CC CB DD 57 18 90 85 61 6F 39 2C 8E AB 03 B3 79 EA E8 96 47 9D AB EB 7E 85 5E 22 1F 98 A8 08 9D 98 D6 43 F4 CD 2F 7A 00 DD 6E BD 82 09 2D 59 69 EE DC C8 6D EF A2 F8 6F A0 35 44 18 17 E4 -[2026-02-20T18:01:57.438212] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 2.5 -[2026-02-20T18:01:57.438226] LOG: [RX FILTER] ✓ RSSI OK (-114 < -30) -[2026-02-20T18:01:57.438233] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:01:57.438239] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:01:57.438254] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:01:57.438261] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:01:57.438268] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:01:57.438333] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:01:57.438487] LOG: [RX FILTER] Decrypted message (51 chars): "Str8OuttaLFP KI7RYA: Nice ! I put a new repeater up" -[2026-02-20T18:01:57.438503] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:01:57.438509] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:01:57.438739] LOG: [RX LOG] Packet heard via last hop: DD, SNR=2.5, path_length=4 -[2026-02-20T18:01:57.438751] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:01:57.438763] LOG: [RX BATCH] First observation for repeater DD: SNR=2.5 -[2026-02-20T18:01:57.438779] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:01:57.438798] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:01:57.438815] LOG: [APP] Immediate RX observation: repeater=DD, snr=2.5, location=47.34201,-122.22225 -[2026-02-20T18:01:57.438828] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:01:57.438844] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34201,-122.22225 (batch tracking: 1 repeaters, rxCount: 9) -[2026-02-20T18:01:57.438863] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:01:57.438876] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=2.5, location=47.34201,-122.22225 -[2026-02-20T18:01:57.439157] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:01:57.439164] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:01:57.439218] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:01:57.602852] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:01:57.603072] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:01:57.645001] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:01:57.645129] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:01:57.645146] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:01:57.645162] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:01:57.703483] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 8e 0a 08 00 00 00 72 23 00 00 -[2026-02-20T18:01:57.703567] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:01:57.703582] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:01:58.044640] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:01:58.044848] LOG: [API QUEUE] Item 1/2: type=RX, external_antenna=true -[2026-02-20T18:01:58.044865] LOG: [API QUEUE] Item 2/2: type=TX, external_antenna=true -[2026-02-20T18:01:58.044881] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:01:58.261657] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:01:58.298735] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:01:58.298763] LOG: [API] Request: {"data":"2 items","items":"RX:external_antenna=true, TX:external_antenna=true"} -[2026-02-20T18:01:58.298767] LOG: [API] Response (200) in 0.25s: {"success":true,"expires_at":1771639618} -[2026-02-20T18:01:58.298773] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:01:58.298778] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:01:58.298990] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:01:58.298997] LOG: [APP] Upload success: +2 items (total: 12) -[2026-02-20T18:02:00.457498] LOG: [GPS SERVICE] Position stream fired: lat=47.34271, lon=-122.22227, accuracy=3.8m -[2026-02-20T18:02:00.457605] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:02:00.457618] LOG: [RX BATCH] Distance check for repeater DD: 78.62m from first observation (threshold=25m) -[2026-02-20T18:02:00.457622] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:02:00.457629] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:02:00.457636] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:02:00.457643] LOG: [RX BATCH] Posting repeater DD: snr=2.5, location=47.34201,-122.22225 -[2026-02-20T18:02:00.457650] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:02:00.457653] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=2.5, location=47.34201,-122.22225 -[2026-02-20T18:02:00.457661] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best 2.50 <= pin 2.50 -[2026-02-20T18:02:00.457667] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 -[2026-02-20T18:02:00.457673] LOG: [APP] Added RX log entry: repeater=DD, snr=2.5, pathLen=4 -[2026-02-20T18:02:00.457693] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:02:00.457696] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:02:02.603858] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:02.774963] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 8e 0a 08 00 00 00 72 23 00 00 -[2026-02-20T18:02:02.775106] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:02.775122] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:03.303085] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:02:03.903497] LOG: [CONN] Frame received (83 bytes): 88 f6 87 15 0b 7b bc e3 28 aa cd be 7a 53 7e dd 81 ba 57 da d0 15 24 78 65 fd 25 aa 70 a7 bd fd 40 8a ff 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 68 80 74 57 ac a4 12 da e9 3c 30 7e c0 9c 59 0e 88 bc f2 33 99 03 2a 71 35 6d 3f 6a e6 e1 2a 40 -[2026-02-20T18:02:03.903639] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:03.903668] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:03.903746] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 7B BC E3 28 AA CD BE 7A 53 7E DD 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 -[2026-02-20T18:02:03.903769] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:02:03.903785] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:02:03.903813] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x7b, lastHop=0xdd, SNR=-2.5, RSSI=-121, payload=67 bytes -[2026-02-20T18:02:03.903831] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:02:03.903843] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:03.903853] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:03.903932] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:03.903949] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 7B BC E3 28 AA CD BE 7A 53 7E DD 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 -[2026-02-20T18:02:03.903972] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: -2.5 -[2026-02-20T18:02:03.903988] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) -[2026-02-20T18:02:03.903999] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:02:03.904014] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:02:03.904028] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:02:03.904040] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:02:03.904056] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:02:03.904142] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:02:03.904294] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.92800, -123.75212 [0.3w]" -[2026-02-20T18:02:03.904317] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:02:03.904333] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:02:03.904361] LOG: [RX LOG] Packet heard via last hop: DD, SNR=-2.5, path_length=11 -[2026-02-20T18:02:03.904373] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:02:03.904389] LOG: [RX BATCH] First observation for repeater DD: SNR=-2.5 -[2026-02-20T18:02:03.904410] LOG: [RX BATCH] Started 30s timeout timer for repeater DD -[2026-02-20T18:02:03.904427] LOG: [RX BATCH] Distance check for repeater DD: 0.00m from first observation (threshold=25m) -[2026-02-20T18:02:03.904452] LOG: [APP] Immediate RX observation: repeater=DD, snr=-2.5, location=47.34271,-122.22227 -[2026-02-20T18:02:03.904470] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:02:03.904530] LOG: [APP] Created IMMEDIATE RX pin for repeater: DD at 47.34271,-122.22227 (batch tracking: 1 repeaters, rxCount: 10) -[2026-02-20T18:02:03.904551] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:02:03.904576] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DD, snr=-2.5, location=47.34271,-122.22227 -[2026-02-20T18:02:03.905035] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:02:03.905053] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:02:03.905067] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:02:05.016505] LOG: [GPS SERVICE] Position stream fired: lat=47.34345, lon=-122.22221, accuracy=3.8m -[2026-02-20T18:02:05.016582] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:02:05.016590] LOG: [RX BATCH] Distance check for repeater DD: 82.07m from first observation (threshold=25m) -[2026-02-20T18:02:05.016595] LOG: [RX BATCH] Distance threshold met for repeater DD, marking for flush -[2026-02-20T18:02:05.016599] LOG: [RX BATCH] Flushing repeater DD -[2026-02-20T18:02:05.016603] LOG: [RX BATCH] Cleared timeout timer for repeater DD -[2026-02-20T18:02:05.016610] LOG: [RX BATCH] Posting repeater DD: snr=-2.5, location=47.34271,-122.22227 -[2026-02-20T18:02:05.016613] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:02:05.016617] LOG: [APP] Finalized RX entry (best SNR): repeater=DD, snr=-2.5, location=47.34271,-122.22227 -[2026-02-20T18:02:05.016624] LOG: [APP] RX pin SNR unchanged for repeater=DD: batch best -2.50 <= pin -2.50 -[2026-02-20T18:02:05.016629] LOG: [APP] Cleared batch tracking for DD: wasPresent=true, remaining=0 -[2026-02-20T18:02:05.016634] LOG: [APP] Added RX log entry: repeater=DD, snr=-2.5, pathLen=11 -[2026-02-20T18:02:05.016648] LOG: [RX BATCH] Repeater DD removed from buffer -[2026-02-20T18:02:05.016651] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:02:05.810794] LOG: [CONN] Frame received (84 bytes): 88 31 c6 15 0c 7b bc e3 28 aa cd be 7a 53 7e dd cc 81 ba 57 da d0 15 24 78 65 fd 25 aa 70 a7 bd fd 40 8a ff 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 68 80 74 57 ac a4 12 da e9 3c 30 7e c0 9c 59 0e 88 bc f2 33 99 03 2a 71 35 6d 3f 6a e6 e1 2a 40 -[2026-02-20T18:02:05.810931] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:05.810960] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:05.811037] LOG: [RX PARSE] RAW Packet (81 bytes): 15 0C 7B BC E3 28 AA CD BE 7A 53 7E DD CC 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 -[2026-02-20T18:02:05.811061] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:02:05.811072] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:02:05.811105] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x7b, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=67 bytes -[2026-02-20T18:02:05.811119] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:02:05.811134] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:05.811144] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:05.811225] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:05.811241] LOG: [RX FILTER] Raw packet (81 bytes): 15 0C 7B BC E3 28 AA CD BE 7A 53 7E DD CC 81 BA 57 DA D0 15 24 78 65 FD 25 AA 70 A7 BD FD 40 8A FF 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 68 80 74 57 AC A4 12 DA E9 3C 30 7E C0 9C 59 0E 88 BC F2 33 99 03 2A 71 35 6D 3F 6A E6 E1 2A 40 -[2026-02-20T18:02:05.811260] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 -[2026-02-20T18:02:05.811279] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:02:05.811291] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:02:05.811301] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:02:05.811318] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:02:05.811332] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:02:05.811347] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:02:05.811432] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:02:05.811579] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.92800, -123.75212 [0.3w]" -[2026-02-20T18:02:05.811601] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:02:05.811616] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:02:05.811642] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=12 -[2026-02-20T18:02:05.811658] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:02:05.811673] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:02:05.811695] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:02:05.811714] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:02:05.811738] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.34345,-122.22221 -[2026-02-20T18:02:05.811756] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:02:05.811779] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34345,-122.22221 (batch tracking: 1 repeaters, rxCount: 11) -[2026-02-20T18:02:05.811798] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:02:05.811843] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.34345,-122.22221 -[2026-02-20T18:02:07.573842] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:02:07.573973] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:02:07.573984] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:02:07.575958] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue -[2026-02-20T18:02:07.606932] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:07.665120] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 08 00 00 00 73 23 00 00 -[2026-02-20T18:02:07.665240] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:07.665265] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:07.893234] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:02:07.893293] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:02:07.893311] LOG: [API] Response (200) in 0.32s: {"success":true,"expires_at":1771639627} -[2026-02-20T18:02:07.893324] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:02:07.893348] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:02:07.896190] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:02:07.896214] LOG: [APP] Upload success: +1 items (total: 13) -[2026-02-20T18:02:08.352601] LOG: [CONN] Frame received (33 bytes): 88 31 c7 01 08 d7 99 ab 50 6c c7 29 cc 68 06 d4 36 45 10 bc c3 bd 11 9f de b9 06 74 7f f2 43 9c 6b -[2026-02-20T18:02:08.352680] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:08.352698] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:08.352717] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B -[2026-02-20T18:02:08.352722] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:02:08.352728] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:02:08.352738] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xd7, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=20 bytes -[2026-02-20T18:02:08.352747] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 -[2026-02-20T18:02:08.352751] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:08.352760] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:08.352776] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:08.352781] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B -[2026-02-20T18:02:08.352788] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 12.25 -[2026-02-20T18:02:08.352796] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:02:08.352800] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:02:08.352820] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:02:08.352826] LOG: [RX LOG] Dropped packet hex: 01 08 D7 99 AB 50 6C C7 29 CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 9C 6B -[2026-02-20T18:02:10.666643] LOG: [CONN] Frame received (38 bytes): 88 30 c7 01 0f d7 99 ab 50 6c 24 38 75 20 20 20 75 e3 7e cc 68 06 d4 36 45 10 bc c3 bd 11 9f de b9 06 74 7f f2 43 -[2026-02-20T18:02:10.666768] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:10.666785] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:10.666805] LOG: [RX PARSE] RAW Packet (35 bytes): 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 -[2026-02-20T18:02:10.666813] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:02:10.666818] LOG: [RX PARSE] Path length offset: 1, Path length: 15 -[2026-02-20T18:02:10.666837] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=15, firstHop=0xd7, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=18 bytes -[2026-02-20T18:02:10.666843] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=15 -[2026-02-20T18:02:10.666850] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:10.666856] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:10.666874] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:10.666879] LOG: [RX FILTER] Raw packet (35 bytes): 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 -[2026-02-20T18:02:10.666888] LOG: [RX FILTER] Header: 0x01 | PathLength: 15 | SNR: 12.0 -[2026-02-20T18:02:10.666894] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:02:10.666902] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:02:10.666928] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:02:10.666933] LOG: [RX LOG] Dropped packet hex: 01 0F D7 99 AB 50 6C 24 38 75 20 20 20 75 E3 7E CC 68 06 D4 36 45 10 BC C3 BD 11 9F DE B9 06 74 7F F2 43 -[2026-02-20T18:02:11.011254] LOG: [GPS SERVICE] Position stream fired: lat=47.34435, lon=-122.22221, accuracy=3.8m -[2026-02-20T18:02:11.011326] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:02:11.011372] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:02:11.011381] LOG: [RX BATCH] Distance check for repeater CC: 99.54m from first observation (threshold=25m) -[2026-02-20T18:02:11.011384] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:02:11.011392] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:02:11.011396] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:02:11.011402] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.34345,-122.22221 -[2026-02-20T18:02:11.011406] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:02:11.011409] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.34345,-122.22221 -[2026-02-20T18:02:11.011416] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:02:11.011421] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:02:11.011425] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=12 -[2026-02-20T18:02:11.011439] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:02:11.011454] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:02:11.011457] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:02:12.602972] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:12.675407] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 -[2026-02-20T18:02:12.675551] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:12.675572] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:12.906429] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:02:17.602686] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:17.650387] LOG: [GPS SERVICE] Position stream fired: lat=47.34528, lon=-122.22221, accuracy=3.8m -[2026-02-20T18:02:17.686701] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 -[2026-02-20T18:02:17.686823] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:17.686838] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:22.573683] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:02:22.573769] LOG: [API QUEUE] Item 1/2: type=RX, external_antenna=true -[2026-02-20T18:02:22.573776] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:02:22.573780] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:02:22.574485] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:02:22.602583] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:22.691552] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 08 00 00 00 73 23 00 00 -[2026-02-20T18:02:22.691641] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:22.691650] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:23.044104] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:02:23.044235] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:02:23.044260] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:02:23.044302] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:02:23.044347] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.34528, -122.22221 [0.3w]" -[2026-02-20T18:02:23.044360] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:02:23.044369] LOG: [TX LOG] Payload: "@[MapperBot] 47.34528, -122.22221 [0.3w]" -[2026-02-20T18:02:23.044388] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:02:23.044402] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:02:23.044417] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:02:23.044430] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:02:23.044451] LOG: [CONN] Sending ping: @[MapperBot] 47.34528, -122.22221 [0.3w] -[2026-02-20T18:02:23.095376] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:02:23.095445] LOG: [API] Request: {"data":"2 items","items":"RX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:02:23.095459] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771639642} -[2026-02-20T18:02:23.095473] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:02:23.095491] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:02:23.095995] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:02:23.096002] LOG: [APP] Upload success: +2 items (total: 15) -[2026-02-20T18:02:23.204903] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:02:23.205030] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:02:23.205050] LOG: [CONN] Received OK response -[2026-02-20T18:02:24.063627] LOG: [CONN] Frame received (73 bytes): 88 30 c6 15 01 cc 81 c4 68 71 36 d7 8f 0f f6 f4 df 4e 50 e6 c6 35 04 0d 83 f5 30 ea b1 a3 ee eb fc 98 03 5f 82 73 0f c8 88 34 2b 27 ec 76 f1 cc bd 5b 67 16 f6 e8 ca 73 48 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:02:24.063726] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:24.063747] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:24.063780] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 C4 68 71 36 D7 8F 0F F6 F4 DF 4E 50 E6 C6 35 04 0D 83 F5 30 EA B1 A3 EE EB FC 98 03 5F 82 73 0F C8 88 34 2B 27 EC 76 F1 CC BD 5B 67 16 F6 E8 CA 73 48 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:02:24.063787] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:02:24.063796] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:02:24.063809] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=67 bytes -[2026-02-20T18:02:24.063817] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:02:24.063824] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:02:24.063830] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-58 -[2026-02-20T18:02:24.063838] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:02:24.063845] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:02:24.063854] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:24.063859] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:24.063864] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:02:26.014495] LOG: [GPS SERVICE] Position stream fired: lat=47.34664, lon=-122.22239, accuracy=3.8m -[2026-02-20T18:02:26.207194] LOG: [PING] Ping sent successfully -[2026-02-20T18:02:27.604353] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:02:27.604457] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:27.706292] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:02:27.706418] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:02:27.706441] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:02:27.706458] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:02:27.764641] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff 88 f8 09 00 00 00 74 23 00 00 -[2026-02-20T18:02:27.764770] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:27.764791] LOG: [CONN] Noise floor updated: -117dBm -[2026-02-20T18:02:28.045263] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:02:28.096913] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:02:31.016796] LOG: [GPS SERVICE] Position stream fired: lat=47.34735, lon=-122.22283, accuracy=3.8m -[2026-02-20T18:02:31.209168] LOG: [PING] RX listening window ended -[2026-02-20T18:02:31.209309] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:02:31.209330] LOG: [GRAPH] Recorded txFail event at -117dBm -[2026-02-20T18:02:31.209382] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:02:31.209396] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:02:31.209406] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:02:31.209423] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:02:31.209438] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:02:31.209743] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:02:31.849570] LOG: [CONN] Frame received (137 bytes): 88 31 c6 11 05 06 c4 7e dd cc 79 5c 55 27 41 aa dd 85 83 05 6d df dc 9c cc 4d cf 33 53 f9 7e 4a 25 d6 57 79 79 97 c1 a5 01 e1 2a 82 99 69 0b a1 e2 4f c1 fe e7 12 3d 6f 54 72 3d ab d0 57 ef 97 c5 af b6 45 71 c1 5e 42 5f 04 c9 84 96 2d c6 49 3f 8e 60 5e c1 a8 da b4 b5 bf 46 39 eb cf 3c 33 86 7d c6 d2 7a a2 a7 dd c6 cb e9 87 2a 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6e 64 73 20 45 76 65 72 79 77 68 65 72 65 -[2026-02-20T18:02:31.849609] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:31.849641] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:31.849707] LOG: [RX PARSE] RAW Packet (134 bytes): 11 05 06 C4 7E DD CC 79 5C 55 27 41 AA DD 85 83 05 6D DF DC 9C CC 4D CF 33 53 F9 7E 4A 25 D6 57 79 79 97 C1 A5 01 E1 2A 82 99 69 0B A1 E2 4F C1 FE E7 12 3D 6F 54 72 3D AB D0 57 EF 97 C5 AF B6 45 71 C1 5E 42 5F 04 C9 84 96 2D C6 49 3F 8E 60 5E C1 A8 DA B4 B5 BF 46 39 EB CF 3C 33 86 7D C6 D2 7A A2 A7 DD C6 CB E9 87 2A 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6E 64 73 20 45 76 65 72 79 77 68 65 72 65 -[2026-02-20T18:02:31.849722] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:02:31.849728] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:02:31.849749] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x06, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=127 bytes -[2026-02-20T18:02:31.849759] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 -[2026-02-20T18:02:31.849767] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:31.849775] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:31.849839] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:31.849849] LOG: [RX FILTER] Raw packet (134 bytes): 11 05 06 C4 7E DD CC 79 5C 55 27 41 AA DD 85 83 05 6D DF DC 9C CC 4D CF 33 53 F9 7E 4A 25 D6 57 79 79 97 C1 A5 01 E1 2A 82 99 69 0B A1 E2 4F C1 FE E7 12 3D 6F 54 72 3D AB D0 57 EF 97 C5 AF B6 45 71 C1 5E 42 5F 04 C9 84 96 2D C6 49 3F 8E 60 5E C1 A8 DA B4 B5 BF 46 39 EB CF 3C 33 86 7D C6 D2 7A A2 A7 DD C6 CB E9 87 2A 05 92 00 00 00 00 00 00 00 00 46 72 69 65 6E 64 73 20 45 76 65 72 79 77 68 65 72 65 -[2026-02-20T18:02:31.849866] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 12.25 -[2026-02-20T18:02:31.849875] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:02:31.849881] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:02:31.849889] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:02:31.849896] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:02:31.849974] LOG: [RX FILTER] ADVERT name extracted: "Friends Everywhere" (18 chars) -[2026-02-20T18:02:31.849988] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:02:31.849995] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Friends Everywhere") -[2026-02-20T18:02:31.850069] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=5 -[2026-02-20T18:02:31.850077] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:02:31.850095] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:02:31.850106] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:02:31.850121] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:02:31.850133] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.34735,-122.22283 -[2026-02-20T18:02:31.850146] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:02:31.850159] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34735,-122.22283 (batch tracking: 1 repeaters, rxCount: 12) -[2026-02-20T18:02:31.850175] LOG: [GRAPH] Recorded rx event at -117dBm with 1 repeater(s) -[2026-02-20T18:02:31.850186] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.34735,-122.22283 -[2026-02-20T18:02:31.850491] LOG: [CONN] Frame received (148 bytes): 8a 79 5c 55 27 41 aa dd 85 83 05 6d df dc 9c cc 4d cf 33 53 f9 7e 4a 25 d6 57 79 79 97 c1 a5 01 e1 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 72 69 65 6e 64 73 20 45 76 65 72 79 77 68 65 72 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2a 82 99 69 00 00 00 00 00 00 00 00 35 12 99 69 -[2026-02-20T18:02:31.850533] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:02:31.850544] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:02:32.602856] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:32.657741] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c6 31 09 00 00 00 74 23 00 00 -[2026-02-20T18:02:32.657874] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:32.657895] LOG: [CONN] Noise floor updated: -117dBm -[2026-02-20T18:02:36.210680] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:02:36.210911] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:02:36.210928] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:02:36.708078] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:02:36.708093] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:02:36.708098] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771639656} -[2026-02-20T18:02:36.708102] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:02:36.708106] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:02:36.708476] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:02:36.708486] LOG: [APP] Upload success: +1 items (total: 16) -[2026-02-20T18:02:37.012768] LOG: [GPS SERVICE] Position stream fired: lat=47.34814, lon=-122.22363, accuracy=3.8m -[2026-02-20T18:02:37.012836] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:02:37.012845] LOG: [RX BATCH] Distance check for repeater CC: 105.92m from first observation (threshold=25m) -[2026-02-20T18:02:37.012848] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:02:37.012851] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:02:37.012856] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:02:37.012861] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.34735,-122.22283 -[2026-02-20T18:02:37.012863] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:02:37.012866] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.34735,-122.22283 -[2026-02-20T18:02:37.012872] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:02:37.012876] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:02:37.012879] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=5 -[2026-02-20T18:02:37.012893] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:02:37.012895] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:02:37.573625] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:02:37.573751] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:02:37.573760] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:02:37.574260] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:02:37.602724] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:37.726850] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 09 00 00 00 74 23 00 00 -[2026-02-20T18:02:37.726902] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:37.726909] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:37.816043] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:02:37.816101] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:02:37.816109] LOG: [API] Response (200) in 0.24s: {"success":true,"expires_at":1771639657} -[2026-02-20T18:02:37.816121] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:02:37.816131] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:02:37.816399] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:02:37.816409] LOG: [APP] Upload success: +1 items (total: 17) -[2026-02-20T18:02:42.602875] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:42.734918] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 09 00 00 00 74 23 00 00 -[2026-02-20T18:02:42.735] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:42.735008] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:42.817733] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:02:46.607108] LOG: [CONN] Frame received (138 bytes): 88 32 c5 11 05 7b 17 7e dd cc 5e 12 ee d8 38 b0 24 70 cc 98 26 f0 a0 7d 67 af 2d bb c8 36 ad 7a 0e 4b 8d 52 0f 75 63 aa 94 36 70 e5 45 66 96 0e bd 84 f3 b4 e9 5a 7d 3f bd 9e 4f 61 e0 72 e5 82 99 c1 5a 01 22 8b 57 2b 8a 6f 0f bb c1 3b c0 28 31 2e c9 32 5c 2f 3f c3 e2 69 ac 02 d6 6b 6f 28 18 0d 3e 1a 75 de 10 b9 7f 7d 7a 34 c6 0b 92 00 00 00 00 00 00 00 00 41 6c 65 78 77 61 72 72 69 6f 72 20 52 6f 6f 66 74 6f 70 -[2026-02-20T18:02:46.607146] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:02:46.607171] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:02:46.607225] LOG: [RX PARSE] RAW Packet (135 bytes): 11 05 7B 17 7E DD CC 5E 12 EE D8 38 B0 24 70 CC 98 26 F0 A0 7D 67 AF 2D BB C8 36 AD 7A 0E 4B 8D 52 0F 75 63 AA 94 36 70 E5 45 66 96 0E BD 84 F3 B4 E9 5A 7D 3F BD 9E 4F 61 E0 72 E5 82 99 C1 5A 01 22 8B 57 2B 8A 6F 0F BB C1 3B C0 28 31 2E C9 32 5C 2F 3F C3 E2 69 AC 02 D6 6B 6F 28 18 0D 3E 1A 75 DE 10 B9 7F 7D 7A 34 C6 0B 92 00 00 00 00 00 00 00 00 41 6C 65 78 77 61 72 72 69 6F 72 20 52 6F 6F 66 74 6F 70 -[2026-02-20T18:02:46.607236] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:02:46.607242] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:02:46.607264] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x7b, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=128 bytes -[2026-02-20T18:02:46.607272] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 -[2026-02-20T18:02:46.607280] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:02:46.607286] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:02:46.607336] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:02:46.607344] LOG: [RX FILTER] Raw packet (135 bytes): 11 05 7B 17 7E DD CC 5E 12 EE D8 38 B0 24 70 CC 98 26 F0 A0 7D 67 AF 2D BB C8 36 AD 7A 0E 4B 8D 52 0F 75 63 AA 94 36 70 E5 45 66 96 0E BD 84 F3 B4 E9 5A 7D 3F BD 9E 4F 61 E0 72 E5 82 99 C1 5A 01 22 8B 57 2B 8A 6F 0F BB C1 3B C0 28 31 2E C9 32 5C 2F 3F C3 E2 69 AC 02 D6 6B 6F 28 18 0D 3E 1A 75 DE 10 B9 7F 7D 7A 34 C6 0B 92 00 00 00 00 00 00 00 00 41 6C 65 78 77 61 72 72 69 6F 72 20 52 6F 6F 66 74 6F 70 -[2026-02-20T18:02:46.607356] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 12.5 -[2026-02-20T18:02:46.607363] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:02:46.607368] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:02:46.607376] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:02:46.607380] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:02:46.607461] LOG: [RX FILTER] ADVERT name extracted: "Alexwarrior Rooftop" (19 chars) -[2026-02-20T18:02:46.607470] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:02:46.607476] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Alexwarrior Rooftop") -[2026-02-20T18:02:46.607550] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=5 -[2026-02-20T18:02:46.607559] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:02:46.607569] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:02:46.607578] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:02:46.607595] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:02:46.607604] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.34814,-122.22363 -[2026-02-20T18:02:46.607616] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:02:46.607627] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.34814,-122.22363 (batch tracking: 1 repeaters, rxCount: 13) -[2026-02-20T18:02:46.607640] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:02:46.607650] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.34814,-122.22363 -[2026-02-20T18:02:46.607884] LOG: [CONN] Frame received (148 bytes): 8a 5e 12 ee d8 38 b0 24 70 cc 98 26 f0 a0 7d 67 af 2d bb c8 36 ad 7a 0e 4b 8d 52 0f 75 63 aa 94 36 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 6c 65 78 77 61 72 72 69 6f 72 20 52 6f 6f 66 74 6f 70 00 00 00 00 00 00 00 00 00 00 00 00 00 70 e5 45 66 00 00 00 00 00 00 00 00 43 12 99 69 -[2026-02-20T18:02:46.607900] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:02:46.607910] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:02:46.737200] LOG: [GPS SERVICE] Position stream fired: lat=47.34922, lon=-122.22479, accuracy=3.8m -[2026-02-20T18:02:46.737282] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:02:46.737298] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:02:46.737308] LOG: [RX BATCH] Distance check for repeater CC: 149.07m from first observation (threshold=25m) -[2026-02-20T18:02:46.737311] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:02:46.737316] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:02:46.737320] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:02:46.737324] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.34814,-122.22363 -[2026-02-20T18:02:46.737351] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:02:46.737354] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.34814,-122.22363 -[2026-02-20T18:02:46.737362] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:02:46.737368] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:02:46.737372] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=5 -[2026-02-20T18:02:46.737387] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:02:46.737404] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:02:46.737408] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:02:47.603609] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:47.713022] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c5 30 09 00 00 00 75 23 00 00 -[2026-02-20T18:02:47.713167] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:47.713187] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:02:51.755408] LOG: [GPS SERVICE] Position stream fired: lat=47.34981, lon=-122.22544, accuracy=3.8m -[2026-02-20T18:02:52.573612] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:02:52.573745] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:02:52.573751] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:02:52.574186] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:02:52.604149] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:52.755917] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 09 00 00 00 75 23 00 00 -[2026-02-20T18:02:52.756042] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:52.756067] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:52.997860] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:02:52.997920] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:02:52.997937] LOG: [API] Response (200) in 0.42s: {"success":true,"expires_at":1771639672} -[2026-02-20T18:02:52.997950] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:02:52.997969] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:02:52.998263] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:02:52.998281] LOG: [APP] Upload success: +1 items (total: 18) -[2026-02-20T18:02:56.736782] LOG: [GPS SERVICE] Position stream fired: lat=47.35040, lon=-122.22609, accuracy=3.9m -[2026-02-20T18:02:57.603564] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:02:57.603813] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:02:57.763465] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:02:57.763553] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:02:57.763562] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:02:57.763575] LOG: [CONN] Battery updated: 4059mV (88%) -[2026-02-20T18:02:57.825455] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 09 00 00 00 75 23 00 00 -[2026-02-20T18:02:57.825581] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:02:57.825603] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:02:57.999063] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:03:01.210627] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:03:01.210749] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:03:01.210762] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:03:01.210796] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:03:01.210864] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35040, -122.22609 [0.3w]" -[2026-02-20T18:03:01.210873] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:03:01.210877] LOG: [TX LOG] Payload: "@[MapperBot] 47.35040, -122.22609 [0.3w]" -[2026-02-20T18:03:01.210883] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:03:01.210893] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:03:01.210898] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:03:01.210905] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:03:01.210915] LOG: [CONN] Sending ping: @[MapperBot] 47.35040, -122.22609 [0.3w] -[2026-02-20T18:03:01.336597] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:03:01.336641] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:03:01.336651] LOG: [CONN] Received OK response -[2026-02-20T18:03:01.752758] LOG: [GPS SERVICE] Position stream fired: lat=47.35103, lon=-122.22676, accuracy=3.8m -[2026-02-20T18:03:02.325804] LOG: [CONN] Frame received (73 bytes): 88 31 c5 15 01 cc 81 35 0e 8c d5 a2 96 98 9f b5 b2 fd 07 99 bb ff d7 71 1b 2d 03 30 c8 23 f1 f2 14 15 28 47 cc c4 fc 0b ef 3e de 07 10 c6 b5 88 f2 4c e7 b5 22 d6 10 8f 6b 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:03:02.325973] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:03:02.326012] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:03:02.326096] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 35 0E 8C D5 A2 96 98 9F B5 B2 FD 07 99 BB FF D7 71 1B 2D 03 30 C8 23 F1 F2 14 15 28 47 CC C4 FC 0B EF 3E DE 07 10 C6 B5 88 F2 4C E7 B5 22 D6 10 8F 6B 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:03:02.326118] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:03:02.326133] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:03:02.326166] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=67 bytes -[2026-02-20T18:03:02.326185] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:03:02.326195] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:03:02.326211] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-59 -[2026-02-20T18:03:02.326222] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:03:02.326233] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:03:02.326250] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:03:02.326260] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:03:02.326271] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:03:02.602987] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:02.682057] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:02.682123] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:02.682131] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:04.334869] LOG: [PING] Ping sent successfully -[2026-02-20T18:03:06.212397] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:03:06.743853] LOG: [GPS SERVICE] Position stream fired: lat=47.35166, lon=-122.22744, accuracy=3.8m -[2026-02-20T18:03:07.575496] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:03:07.575620] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:03:07.602876] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:07.694922] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:07.695056] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:07.695083] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:09.335600] LOG: [PING] RX listening window ended -[2026-02-20T18:03:09.335664] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:03:09.335675] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:03:09.335702] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:03:09.335709] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:03:09.335713] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:03:09.335720] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:03:09.335727] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:03:09.335846] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:03:11.739034] LOG: [GPS SERVICE] Position stream fired: lat=47.35228, lon=-122.22805, accuracy=3.8m -[2026-02-20T18:03:11.862260] LOG: [CONN] Frame received (87 bytes): 88 2e c4 15 13 62 1f 7e 75 20 20 20 20 20 20 20 20 20 20 20 53 7e 48 cc ca 17 54 6e ed f2 21 c8 48 a2 de de bc d5 4e f3 34 11 a8 c6 ce 07 11 ca 75 a8 7c fb 4c 18 0c 5b 5f ea a6 bd 68 3d bf 59 a9 26 c0 c6 b7 6d 78 29 e4 9c e0 ea c9 59 71 06 81 e8 5f df d6 7a a6 -[2026-02-20T18:03:11.862339] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:03:11.862353] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:03:11.862389] LOG: [RX PARSE] RAW Packet (84 bytes): 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 -[2026-02-20T18:03:11.862399] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:03:11.862404] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:03:11.862421] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x62, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=63 bytes -[2026-02-20T18:03:11.862428] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:03:11.862435] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:03:11.862441] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:03:11.862473] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:03:11.862495] LOG: [RX FILTER] Raw packet (84 bytes): 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 -[2026-02-20T18:03:11.862503] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 11.5 -[2026-02-20T18:03:11.862511] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:03:11.862615] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:03:11.862620] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:03:11.862628] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:03:11.862634] LOG: [RX FILTER] Encrypted message: 60 bytes -[2026-02-20T18:03:11.862639] LOG: [CRYPTO] Decrypting message (60 bytes) -[2026-02-20T18:03:11.862728] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:03:11.862753] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:03:11.862850] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:03:11.862886] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:03:11.862892] LOG: [RX LOG] Dropped packet hex: 15 13 62 1F 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 48 CC CA 17 54 6E ED F2 21 C8 48 A2 DE DE BC D5 4E F3 34 11 A8 C6 CE 07 11 CA 75 A8 7C FB 4C 18 0C 5B 5F EA A6 BD 68 3D BF 59 A9 26 C0 C6 B7 6D 78 29 E4 9C E0 EA C9 59 71 06 81 E8 5F DF D6 7A A6 -[2026-02-20T18:03:12.603948] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:12.675667] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:12.675801] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:12.675821] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:14.336751] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:03:14.336894] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:03:14.336904] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:03:14.767828] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:03:14.767873] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:03:14.767880] LOG: [API] Response (200) in 0.43s: {"success":true,"expires_at":1771639694} -[2026-02-20T18:03:14.767888] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:03:14.767899] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:03:14.768226] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:03:14.768247] LOG: [APP] Upload success: +1 items (total: 19) -[2026-02-20T18:03:16.754776] LOG: [GPS SERVICE] Position stream fired: lat=47.35288, lon=-122.22848, accuracy=3.8m -[2026-02-20T18:03:16.754814] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:03:16.754867] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:03:17.608900] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:17.684608] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:17.684744] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:17.684770] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:19.768683] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:03:21.749952] LOG: [GPS SERVICE] Position stream fired: lat=47.35341, lon=-122.22884, accuracy=3.8m -[2026-02-20T18:03:22.573685] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:03:22.573806] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:03:22.602711] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:22.692452] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:22.692532] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:22.692542] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:03:26.772569] LOG: [GPS SERVICE] Position stream fired: lat=47.35365, lon=-122.22850, accuracy=3.8m -[2026-02-20T18:03:27.602988] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:03:27.603236] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:27.764929] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:03:27.765078] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:03:27.765097] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:03:27.765113] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:03:27.826250] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:27.826370] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:27.826395] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:31.747284] LOG: [GPS SERVICE] Position stream fired: lat=47.35367, lon=-122.22759, accuracy=3.8m -[2026-02-20T18:03:32.602887] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:32.745424] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:32.745559] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:32.745578] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:36.765767] LOG: [GPS SERVICE] Position stream fired: lat=47.35367, lon=-122.22638, accuracy=3.8m -[2026-02-20T18:03:37.574072] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:03:37.574299] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:03:37.604085] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:37.665144] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:37.665282] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:37.665302] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:39.337032] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:03:39.337202] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:03:39.337232] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:03:39.337269] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:03:39.337311] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35367, -122.22638 [0.3w]" -[2026-02-20T18:03:39.337323] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:03:39.337330] LOG: [TX LOG] Payload: "@[MapperBot] 47.35367, -122.22638 [0.3w]" -[2026-02-20T18:03:39.337345] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:03:39.337355] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:03:39.337364] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:03:39.337378] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:03:39.337394] LOG: [CONN] Sending ping: @[MapperBot] 47.35367, -122.22638 [0.3w] -[2026-02-20T18:03:39.523082] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:03:39.523223] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:03:39.523237] LOG: [CONN] Received OK response -[2026-02-20T18:03:40.518211] LOG: [CONN] Frame received (73 bytes): 88 2f c8 15 01 cc 81 f6 89 1c f0 45 81 d7 f4 61 18 9c f8 4d 2b 9e e1 bc 51 8f 30 ae 2f f4 b1 52 29 27 03 04 a5 25 c7 b5 e3 c9 cf 2d 9e e9 99 79 cf ef 80 eb 1b ac 62 06 06 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:03:40.518376] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:03:40.518407] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:03:40.518481] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 F6 89 1C F0 45 81 D7 F4 61 18 9C F8 4D 2B 9E E1 BC 51 8F 30 AE 2F F4 B1 52 29 27 03 04 A5 25 C7 B5 E3 C9 CF 2D 9E E9 99 79 CF EF 80 EB 1B AC 62 06 06 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:03:40.518503] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:03:40.518625] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:03:40.518690] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=67 bytes -[2026-02-20T18:03:40.518702] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:03:40.518709] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:03:40.518724] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-56 -[2026-02-20T18:03:40.518732] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:03:40.518767] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:03:40.518777] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:03:40.518784] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:03:40.518796] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:03:41.778218] LOG: [GPS SERVICE] Position stream fired: lat=47.35369, lon=-122.22518, accuracy=3.8m -[2026-02-20T18:03:42.525248] LOG: [PING] Ping sent successfully -[2026-02-20T18:03:42.603058] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:42.884414] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:42.884571] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:42.884592] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:44.337919] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:03:46.763967] LOG: [GPS SERVICE] Position stream fired: lat=47.35366, lon=-122.22404, accuracy=3.8m -[2026-02-20T18:03:46.764018] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:03:46.764098] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:03:47.525734] LOG: [PING] RX listening window ended -[2026-02-20T18:03:47.525915] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:03:47.525944] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:03:47.526017] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:03:47.526037] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:03:47.526050] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:03:47.526077] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:03:47.526094] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:03:47.529863] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:03:47.603046] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:47.894422] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 09 00 00 00 75 23 00 00 -[2026-02-20T18:03:47.894651] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:47.894673] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:03:50.030029] LOG: [CONN] Frame received (91 bytes): 88 2f c8 15 03 75 7e cc 23 53 d8 8d 38 18 93 9d ce 82 a4 72 bd 69 0a d6 f1 ef 45 b7 69 79 87 2c 71 89 bb c4 06 5a 0c 8a 2e 40 4d 4b 42 31 e4 d1 2d bb 5a 2e 8c 63 ff 1b cf 4a 3c 56 54 04 cb 89 2a c9 91 c8 67 66 1d be d9 f3 1a 34 5d 76 c3 f6 10 1b 79 cb f0 9b f3 bb 2b 9a 97 -[2026-02-20T18:03:50.030149] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:03:50.030174] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:03:50.030247] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 -[2026-02-20T18:03:50.030262] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:03:50.030274] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:03:50.030293] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0x75, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=83 bytes -[2026-02-20T18:03:50.030307] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:03:50.030317] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:03:50.030324] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:03:50.030386] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:03:50.030397] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 -[2026-02-20T18:03:50.030414] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.75 -[2026-02-20T18:03:50.030426] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:03:50.030435] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:03:50.030448] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:03:50.030458] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:03:50.030664] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:03:50.030674] LOG: [RX LOG] Dropped packet hex: 15 03 75 7E CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B 9A 97 -[2026-02-20T18:03:51.761673] LOG: [GPS SERVICE] Position stream fired: lat=47.35364, lon=-122.22300, accuracy=3.8m -[2026-02-20T18:03:52.531222] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:03:52.531483] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:03:52.531501] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:03:52.575422] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:03:52.575523] LOG: [API QUEUE] Upload skipped: already uploading -[2026-02-20T18:03:52.602886] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:52.782650] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 2f 09 00 00 00 76 23 00 00 -[2026-02-20T18:03:52.782697] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:52.782702] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:03:52.976647] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:03:52.976730] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:03:52.976753] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639732} -[2026-02-20T18:03:52.976771] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:03:52.976795] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:03:52.977709] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:03:52.977728] LOG: [APP] Upload success: +1 items (total: 20) -[2026-02-20T18:03:56.748033] LOG: [GPS SERVICE] Position stream fired: lat=47.35364, lon=-122.22210, accuracy=3.8m -[2026-02-20T18:03:57.602648] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:03:57.602747] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:03:57.645369] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:03:57.645465] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:03:57.645478] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:03:57.645495] LOG: [CONN] Battery updated: 4069mV (89%) -[2026-02-20T18:03:57.701773] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 2f 09 00 00 00 76 23 00 00 -[2026-02-20T18:03:57.701839] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:03:57.701848] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:03:57.978865] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:04:00.841708] LOG: [CONN] Frame received (96 bytes): 88 31 c7 15 0a 75 7e 75 20 20 20 75 7e 2a cc 23 53 d8 8d 38 18 93 9d ce 82 a4 72 bd 69 0a d6 f1 ef 45 b7 69 79 87 2c 71 89 bb c4 06 5a 0c 8a 2e 40 4d 4b 42 31 e4 d1 2d bb 5a 2e 8c 63 ff 1b cf 4a 3c 56 54 04 cb 89 2a c9 91 c8 67 66 1d be d9 f3 1a 34 5d 76 c3 f6 10 1b 79 cb f0 9b f3 bb 2b -[2026-02-20T18:04:00.841852] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:00.841887] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:00.841971] LOG: [RX PARSE] RAW Packet (93 bytes): 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B -[2026-02-20T18:04:00.841994] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:00.842005] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:04:00.842032] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x75, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=81 bytes -[2026-02-20T18:04:00.842047] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:04:00.842062] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:00.842074] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:00.842150] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:00.842297] LOG: [RX FILTER] Raw packet (93 bytes): 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B -[2026-02-20T18:04:00.842349] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 -[2026-02-20T18:04:00.842367] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:04:00.842379] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:00.842395] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:00.842407] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:00.842558] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:00.842572] LOG: [RX LOG] Dropped packet hex: 15 0A 75 7E 75 20 20 20 75 7E 2A CC 23 53 D8 8D 38 18 93 9D CE 82 A4 72 BD 69 0A D6 F1 EF 45 B7 69 79 87 2C 71 89 BB C4 06 5A 0C 8A 2E 40 4D 4B 42 31 E4 D1 2D BB 5A 2E 8C 63 FF 1B CF 4A 3C 56 54 04 CB 89 2A C9 91 C8 67 66 1D BE D9 F3 1A 34 5D 76 C3 F6 10 1B 79 CB F0 9B F3 BB 2B -[2026-02-20T18:04:01.764191] LOG: [GPS SERVICE] Position stream fired: lat=47.35365, lon=-122.22127, accuracy=3.8m -[2026-02-20T18:04:02.605993] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:02.683044] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 09 00 00 00 76 23 00 00 -[2026-02-20T18:04:02.683139] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:02.683153] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:06.758108] LOG: [GPS SERVICE] Position stream fired: lat=47.35368, lon=-122.22033, accuracy=3.8m -[2026-02-20T18:04:07.367676] LOG: [CONN] Frame received (92 bytes): 88 30 c8 15 04 c7 9b dd cc 81 7a 2f 32 aa 19 11 7a ae ff fa 3c 2e a5 30 7b 53 e7 43 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 65 72 d7 56 d4 00 dd 59 24 5a f4 d0 d7 d1 f8 7a ec 88 d2 05 50 2e 05 93 6c f6 47 01 d9 11 94 cf -[2026-02-20T18:04:07.367805] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:07.367837] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:07.367880] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 C7 9B DD CC 81 7A 2F 32 AA 19 11 7A AE FF FA 3C 2E A5 30 7B 53 E7 43 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 65 72 D7 56 D4 00 DD 59 24 5A F4 D0 D7 D1 F8 7A EC 88 D2 05 50 2E 05 93 6C F6 47 01 D9 11 94 CF -[2026-02-20T18:04:07.367892] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:07.367897] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:04:07.367929] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=83 bytes -[2026-02-20T18:04:07.367941] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:04:07.367951] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:07.367961] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:07.368002] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:07.368015] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 C7 9B DD CC 81 7A 2F 32 AA 19 11 7A AE FF FA 3C 2E A5 30 7B 53 E7 43 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 65 72 D7 56 D4 00 DD 59 24 5A F4 D0 D7 D1 F8 7A EC 88 D2 05 50 2E 05 93 6C F6 47 01 D9 11 94 CF -[2026-02-20T18:04:07.368028] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 -[2026-02-20T18:04:07.368042] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:04:07.368048] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:07.368056] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:04:07.368066] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:04:07.368072] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:04:07.368082] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:04:07.368140] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:04:07.368252] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.39362, -122.50339 [..." -[2026-02-20T18:04:07.368263] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:04:07.368271] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:04:07.368289] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 -[2026-02-20T18:04:07.368295] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:04:07.368304] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 -[2026-02-20T18:04:07.368313] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:04:07.368323] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:04:07.368335] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.35368,-122.22033 -[2026-02-20T18:04:07.368344] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:04:07.368356] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35368,-122.22033 (batch tracking: 1 repeaters, rxCount: 14) -[2026-02-20T18:04:07.368367] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:04:07.368388] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.35368,-122.22033 -[2026-02-20T18:04:07.368583] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:04:07.368591] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:04:07.368598] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:04:07.573632] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:04:07.573736] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:04:07.602995] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:07.723629] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 30 09 00 00 00 76 23 00 00 -[2026-02-20T18:04:07.723704] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:07.723719] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:10.364739] LOG: [CONN] Frame received (28 bytes): 88 30 c7 15 04 32 9d dd cc ca c2 eb 86 2a 26 d9 05 50 19 72 38 91 60 83 00 e2 00 a2 -[2026-02-20T18:04:10.364887] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:10.364922] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:10.364964] LOG: [RX PARSE] RAW Packet (25 bytes): 15 04 32 9D DD CC CA C2 EB 86 2A 26 D9 05 50 19 72 38 91 60 83 00 E2 00 A2 -[2026-02-20T18:04:10.364977] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:10.364992] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:04:10.365016] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=19 bytes -[2026-02-20T18:04:10.365035] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:04:10.365048] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:10.365057] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:10.365093] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:10.365110] LOG: [RX FILTER] Raw packet (25 bytes): 15 04 32 9D DD CC CA C2 EB 86 2A 26 D9 05 50 19 72 38 91 60 83 00 E2 00 A2 -[2026-02-20T18:04:10.365126] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 -[2026-02-20T18:04:10.365140] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:04:10.365157] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:10.365167] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:10.365179] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:10.365196] LOG: [RX FILTER] Encrypted message: 16 bytes -[2026-02-20T18:04:10.365207] LOG: [CRYPTO] Decrypting message (16 bytes) -[2026-02-20T18:04:10.365272] LOG: [CRYPTO] Decrypted successfully (16 bytes) -[2026-02-20T18:04:10.365438] LOG: [RX FILTER] Decrypted message (11 chars): "Lilygo1w: T" -[2026-02-20T18:04:10.365461] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:04:10.365477] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:04:10.365508] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 -[2026-02-20T18:04:10.365525] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:04:10.365542] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.0, new=12.0 -[2026-02-20T18:04:10.365570] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:04:10.365589] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.0, current_best=12.0 -[2026-02-20T18:04:11.690496] LOG: [CONN] Frame received (61 bytes): 88 30 c7 15 05 f7 53 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 ef 5c fa 4d f2 e9 3d ab 68 65 0b 73 62 91 38 f9 26 cb a5 5e cc 6e 9f 6c 61 6b 18 6d f9 e6 -[2026-02-20T18:04:11.690612] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:11.690656] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:11.690719] LOG: [RX PARSE] RAW Packet (58 bytes): 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 -[2026-02-20T18:04:11.690735] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:11.690746] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:04:11.690775] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0xf7, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=51 bytes -[2026-02-20T18:04:11.690788] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T18:04:11.690805] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:11.690816] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:11.690875] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:11.690887] LOG: [RX FILTER] Raw packet (58 bytes): 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 -[2026-02-20T18:04:11.690908] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 -[2026-02-20T18:04:11.690922] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:04:11.690933] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:11.690957] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:11.690968] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:11.691143] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:11.691162] LOG: [RX LOG] Dropped packet hex: 15 05 F7 53 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B 18 6D F9 E6 -[2026-02-20T18:04:11.751175] LOG: [GPS SERVICE] Position stream fired: lat=47.35370, lon=-122.21909, accuracy=3.8m -[2026-02-20T18:04:11.751238] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:04:11.751246] LOG: [RX BATCH] Distance check for repeater CC: 93.74m from first observation (threshold=25m) -[2026-02-20T18:04:11.751251] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:04:11.751254] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:04:11.751258] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:04:11.751264] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.35368,-122.22033 -[2026-02-20T18:04:11.751267] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:04:11.751271] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.35368,-122.22033 -[2026-02-20T18:04:11.751276] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 -[2026-02-20T18:04:11.751280] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:04:11.751284] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 -[2026-02-20T18:04:11.751298] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:04:11.751300] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:04:12.602889] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:12.644135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 77 23 00 00 -[2026-02-20T18:04:12.644275] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:12.644295] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:16.754591] LOG: [GPS SERVICE] Position stream fired: lat=47.35370, lon=-122.21774, accuracy=3.8m -[2026-02-20T18:04:17.527227] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:04:17.527428] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:04:17.527448] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:04:17.527497] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:04:17.527554] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35370, -122.21774 [0.3w]" -[2026-02-20T18:04:17.527572] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:04:17.527582] LOG: [TX LOG] Payload: "@[MapperBot] 47.35370, -122.21774 [0.3w]" -[2026-02-20T18:04:17.527597] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:04:17.527616] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:04:17.527630] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:04:17.527641] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:04:17.527669] LOG: [CONN] Sending ping: @[MapperBot] 47.35370, -122.21774 [0.3w] -[2026-02-20T18:04:17.602791] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:17.654185] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:04:17.654304] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:04:17.654318] LOG: [CONN] Received OK response -[2026-02-20T18:04:17.712878] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 77 23 00 00 -[2026-02-20T18:04:17.713004] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:17.713026] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:18.268278] LOG: [CONN] Frame received (65 bytes): 88 32 c8 15 0d f7 53 20 20 20 20 20 53 c3 7a 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 ef 5c fa 4d f2 e9 3d ab 68 65 0b 73 62 91 38 f9 26 cb a5 5e cc 6e 9f 6c 61 6b -[2026-02-20T18:04:18.268365] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:18.268381] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:18.268408] LOG: [RX PARSE] RAW Packet (62 bytes): 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B -[2026-02-20T18:04:18.268419] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:18.268423] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:04:18.268439] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=47 bytes -[2026-02-20T18:04:18.268447] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:04:18.268450] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:18.268456] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 -[2026-02-20T18:04:18.268460] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:18.268466] LOG: [TX LOG] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:04:18.268474] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 -[2026-02-20T18:04:18.268478] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:04:18.268483] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:18.268490] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:18.268514] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:18.268518] LOG: [RX FILTER] Raw packet (62 bytes): 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B -[2026-02-20T18:04:18.268527] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.5 -[2026-02-20T18:04:18.268532] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:04:18.268536] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:18.268542] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:18.268548] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:18.268575] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:18.268579] LOG: [RX LOG] Dropped packet hex: 15 0D F7 53 20 20 20 20 20 53 C3 7A 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 EF 5C FA 4D F2 E9 3D AB 68 65 0B 73 62 91 38 F9 26 CB A5 5E CC 6E 9F 6C 61 6B -[2026-02-20T18:04:18.800983] LOG: [CONN] Frame received (73 bytes): 88 34 c7 15 01 cc 81 88 5d e5 07 19 0b 64 e1 7d c7 94 e2 77 c9 49 a7 98 43 a0 1d 5a 29 8d b7 bd 90 28 4f 0f 1c 79 bb 02 23 8e 88 50 dd 6c 01 f5 46 6a ce 8f b7 04 36 7c 9a 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:04:18.801164] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:18.801201] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:18.801280] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 88 5D E5 07 19 0B 64 E1 7D C7 94 E2 77 C9 49 A7 98 43 A0 1D 5A 29 8D B7 BD 90 28 4F 0F 1C 79 BB 02 23 8E 88 50 DD 6C 01 F5 46 6A CE 8F B7 04 36 7C 9A 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:04:18.801302] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:18.801313] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:04:18.801352] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=13.0, RSSI=-57, payload=67 bytes -[2026-02-20T18:04:18.801365] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:04:18.801380] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:18.801395] LOG: [TX LOG] Processing rx_log entry: SNR=13.0, RSSI=-57 -[2026-02-20T18:04:18.801405] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:18.801421] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:04:18.801434] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:18.801449] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:18.801462] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:04:20.656765] LOG: [PING] Ping sent successfully -[2026-02-20T18:04:21.179525] LOG: [CONN] Frame received (41 bytes): 88 32 c6 15 13 f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7e dd cc 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 -[2026-02-20T18:04:21.179615] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:21.179633] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:21.179654] LOG: [RX PARSE] RAW Packet (38 bytes): 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 -[2026-02-20T18:04:21.179662] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:21.179668] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:04:21.179679] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=17 bytes -[2026-02-20T18:04:21.179687] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:04:21.179691] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:21.179696] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 -[2026-02-20T18:04:21.179705] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:21.179711] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:21.179718] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x19, expected=0x81 -[2026-02-20T18:04:21.179723] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:04:21.179728] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:21.179736] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:21.179756] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:21.179761] LOG: [RX FILTER] Raw packet (38 bytes): 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 -[2026-02-20T18:04:21.179770] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.5 -[2026-02-20T18:04:21.179775] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:21.179780] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:21.179788] LOG: [RX FILTER] Channel hash: 0x19 -[2026-02-20T18:04:21.179793] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 -[2026-02-20T18:04:21.179820] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:21.179824] LOG: [RX LOG] Dropped packet hex: 15 13 F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 53 7E DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 -[2026-02-20T18:04:21.765514] LOG: [GPS SERVICE] Position stream fired: lat=47.35372, lon=-122.21634, accuracy=3.8m -[2026-02-20T18:04:21.765562] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:04:21.765628] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:04:22.008148] LOG: [CONN] Frame received (44 bytes): 88 31 c6 15 12 f7 53 20 20 20 20 20 20 20 20 20 75 26 07 f4 7e dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 86 -[2026-02-20T18:04:22.008328] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:22.008358] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:22.008405] LOG: [RX PARSE] RAW Packet (41 bytes): 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 -[2026-02-20T18:04:22.008425] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:22.008436] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:04:22.008468] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xf7, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=21 bytes -[2026-02-20T18:04:22.008481] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T18:04:22.008505] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:22.008517] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-58 -[2026-02-20T18:04:22.008528] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:22.008546] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:22.008559] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 -[2026-02-20T18:04:22.008570] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:04:22.008588] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:22.008599] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:22.008640] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:22.008658] LOG: [RX FILTER] Raw packet (41 bytes): 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 -[2026-02-20T18:04:22.008674] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.25 -[2026-02-20T18:04:22.008692] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:22.008703] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:22.008713] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:22.008729] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:22.008779] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:22.008795] LOG: [RX LOG] Dropped packet hex: 15 12 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 86 -[2026-02-20T18:04:22.413007] LOG: [CONN] Frame received (45 bytes): 88 33 c6 15 15 f7 53 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 c7 32 2a dd cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 -[2026-02-20T18:04:22.413135] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:22.413164] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:22.413212] LOG: [RX PARSE] RAW Packet (42 bytes): 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 -[2026-02-20T18:04:22.413230] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:22.413241] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:04:22.413272] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xf7, lastHop=0xcc, SNR=12.75, RSSI=-58, payload=19 bytes -[2026-02-20T18:04:22.413287] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:04:22.413296] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:22.413311] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-58 -[2026-02-20T18:04:22.413322] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:22.413335] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:22.413352] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 -[2026-02-20T18:04:22.413363] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:04:22.413378] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:22.413389] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:22.413439] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:22.413450] LOG: [RX FILTER] Raw packet (42 bytes): 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 -[2026-02-20T18:04:22.413470] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.75 -[2026-02-20T18:04:22.413482] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:22.413497] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:22.413508] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:22.413518] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:22.413570] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:22.413582] LOG: [RX LOG] Dropped packet hex: 15 15 F7 53 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 C7 32 2A DD CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 -[2026-02-20T18:04:22.528774] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:04:22.573712] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:04:22.573842] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:04:22.573849] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:04:22.574266] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:04:22.602654] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:22.753320] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 33 09 00 00 00 78 23 00 00 -[2026-02-20T18:04:22.753397] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:22.753409] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:23.016480] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:04:23.016567] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:04:23.016584] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639762} -[2026-02-20T18:04:23.016602] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:04:23.016627] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:04:23.017191] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:04:23.017222] LOG: [APP] Upload success: +1 items (total: 21) -[2026-02-20T18:04:25.658942] LOG: [PING] RX listening window ended -[2026-02-20T18:04:25.659108] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:04:25.659142] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:04:25.659218] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:04:25.659231] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:04:25.659248] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:04:25.659272] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:04:25.659293] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:04:25.659999] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:04:26.611030] LOG: [CONN] Frame received (47 bytes): 88 30 c6 15 1d f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2b 97 19 1f ab 7e 2a dd cc 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b -[2026-02-20T18:04:26.611088] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:26.611127] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:26.611174] LOG: [RX PARSE] RAW Packet (44 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B -[2026-02-20T18:04:26.611195] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:26.611207] LOG: [RX PARSE] Path length offset: 1, Path length: 29 -[2026-02-20T18:04:26.611233] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=29, firstHop=0xf7, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=13 bytes -[2026-02-20T18:04:26.611249] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=29 -[2026-02-20T18:04:26.611260] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:26.611276] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:26.611322] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:26.611334] LOG: [RX FILTER] Raw packet (44 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B -[2026-02-20T18:04:26.611355] LOG: [RX FILTER] Header: 0x15 | PathLength: 29 | SNR: 12.0 -[2026-02-20T18:04:26.611370] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:26.611385] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:26.611399] LOG: [RX FILTER] Channel hash: 0x19 -[2026-02-20T18:04:26.611410] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 -[2026-02-20T18:04:26.611577] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:26.611596] LOG: [RX LOG] Dropped packet hex: 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 75 2B 97 19 1F AB 7E 2A DD CC 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B -[2026-02-20T18:04:26.745194] LOG: [GPS SERVICE] Position stream fired: lat=47.35371, lon=-122.21487, accuracy=3.8m -[2026-02-20T18:04:27.605110] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:04:27.605307] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:27.704931] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:04:27.705030] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:04:27.705047] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:04:27.705059] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:04:27.763572] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 09 00 00 00 78 23 00 00 -[2026-02-20T18:04:27.763649] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:27.763658] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:28.017950] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:04:28.692612] LOG: [CONN] Frame received (41 bytes): 88 32 c4 15 1d f7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7e dd cc 19 ad c8 2f 00 d1 d6 -[2026-02-20T18:04:28.692676] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:28.692689] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:28.692701] LOG: [RX PARSE] RAW Packet (38 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 -[2026-02-20T18:04:28.692705] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:28.692710] LOG: [RX PARSE] Path length offset: 1, Path length: 29 -[2026-02-20T18:04:28.692717] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=29, firstHop=0xf7, lastHop=0xcc, SNR=12.5, RSSI=-60, payload=7 bytes -[2026-02-20T18:04:28.692721] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=29 -[2026-02-20T18:04:28.692725] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:28.692727] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:28.692736] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:28.692742] LOG: [RX FILTER] Raw packet (38 bytes): 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 -[2026-02-20T18:04:28.692745] LOG: [RX FILTER] Header: 0x15 | PathLength: 29 | SNR: 12.5 -[2026-02-20T18:04:28.692750] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:04:28.692754] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:28.692756] LOG: [RX FILTER] Channel hash: 0x19 -[2026-02-20T18:04:28.692761] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x19 -[2026-02-20T18:04:28.692776] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:28.692780] LOG: [RX LOG] Dropped packet hex: 15 1D F7 53 20 20 20 20 20 20 20 20 20 20 20 23 20 20 20 20 20 20 20 20 20 20 20 75 7E DD CC 19 AD C8 2F 00 D1 D6 -[2026-02-20T18:04:30.568477] LOG: [CONN] Frame received (48 bytes): 88 30 c6 15 27 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e e8 48 1b cc ca c2 eb 86 -[2026-02-20T18:04:30.568563] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:30.568585] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:30.568638] LOG: [RX PARSE] RAW Packet (45 bytes): 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 -[2026-02-20T18:04:30.568647] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:30.568652] LOG: [RX PARSE] Path length offset: 1, Path length: 39 -[2026-02-20T18:04:30.568662] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=39, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=4 bytes -[2026-02-20T18:04:30.568671] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=39 -[2026-02-20T18:04:30.568676] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:30.568682] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:30.568706] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:30.568714] LOG: [RX FILTER] Raw packet (45 bytes): 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 -[2026-02-20T18:04:30.568724] LOG: [RX FILTER] Header: 0x15 | PathLength: 39 | SNR: 12.0 -[2026-02-20T18:04:30.568734] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:30.568739] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:30.568746] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:30.568755] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:30.568762] LOG: [RX FILTER] Encrypted message: 1 bytes -[2026-02-20T18:04:30.568769] LOG: [CRYPTO] Decrypting message (1 bytes) -[2026-02-20T18:04:30.568847] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:30.568873] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:30.568994] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:04:30.569036] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:04:30.569044] LOG: [RX LOG] Dropped packet hex: 15 27 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E E8 48 1B CC CA C2 EB 86 -[2026-02-20T18:04:30.660756] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:04:30.660978] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:04:30.660995] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:04:30.915214] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:04:30.915317] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:04:30.915333] LOG: [API] Response (200) in 0.25s: {"success":true,"expires_at":1771639770} -[2026-02-20T18:04:30.915357] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:04:30.915376] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:04:30.918708] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:04:30.918731] LOG: [APP] Upload success: +1 items (total: 22) -[2026-02-20T18:04:31.772246] LOG: [GPS SERVICE] Position stream fired: lat=47.35378, lon=-122.21333, accuracy=3.8m -[2026-02-20T18:04:32.602951] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:32.713349] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 09 00 00 00 78 23 00 00 -[2026-02-20T18:04:32.713486] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:32.713521] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:32.959017] LOG: [CONN] Frame received (53 bytes): 88 30 c6 15 2c 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e 64 91 f0 a5 7a 7e 2a dd cc ca c2 eb 8e -[2026-02-20T18:04:32.959148] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:32.959174] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:32.959221] LOG: [RX PARSE] RAW Packet (50 bytes): 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E -[2026-02-20T18:04:32.959233] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:32.959241] LOG: [RX PARSE] Path length offset: 1, Path length: 44 -[2026-02-20T18:04:32.959274] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=44, firstHop=0x32, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=4 bytes -[2026-02-20T18:04:32.959285] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=44 -[2026-02-20T18:04:32.959299] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:32.959307] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:32.959347] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:32.959367] LOG: [RX FILTER] Raw packet (50 bytes): 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E -[2026-02-20T18:04:32.959380] LOG: [RX FILTER] Header: 0x15 | PathLength: 44 | SNR: 12.0 -[2026-02-20T18:04:32.959398] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:32.959406] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:32.959414] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:32.959431] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:32.959441] LOG: [RX FILTER] Encrypted message: 1 bytes -[2026-02-20T18:04:32.959453] LOG: [CRYPTO] Decrypting message (1 bytes) -[2026-02-20T18:04:32.959585] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:32.959629] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:32.959866] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:04:32.959945] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:04:32.959954] LOG: [RX LOG] Dropped packet hex: 15 2C 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A 7E 2A DD CC CA C2 EB 8E -[2026-02-20T18:04:33.291326] LOG: [CONN] Frame received (51 bytes): 88 2d c6 15 19 f7 53 20 20 20 20 20 20 20 20 20 75 26 07 f4 7e e8 86 75 83 1f ab 7e 1b cc 23 19 ad c8 2f 00 d1 d6 6e 32 ce 4d f4 8b 7e 73 8c d6 e9 4c 26 -[2026-02-20T18:04:33.291485] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:33.291515] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:33.291575] LOG: [RX PARSE] RAW Packet (48 bytes): 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 -[2026-02-20T18:04:33.291594] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:33.291606] LOG: [RX PARSE] Path length offset: 1, Path length: 25 -[2026-02-20T18:04:33.291640] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=25, firstHop=0xf7, lastHop=0xcc, SNR=11.25, RSSI=-58, payload=21 bytes -[2026-02-20T18:04:33.291655] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=25 -[2026-02-20T18:04:33.291670] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:33.291681] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:33.291726] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:33.291737] LOG: [RX FILTER] Raw packet (48 bytes): 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 -[2026-02-20T18:04:33.291757] LOG: [RX FILTER] Header: 0x15 | PathLength: 25 | SNR: 11.25 -[2026-02-20T18:04:33.291771] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:04:33.291787] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:33.291797] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:04:33.291808] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:04:33.291869] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:04:33.291885] LOG: [RX LOG] Dropped packet hex: 15 19 F7 53 20 20 20 20 20 20 20 20 20 75 26 07 F4 7E E8 86 75 83 1F AB 7E 1B CC 23 19 AD C8 2F 00 D1 D6 6E 32 CE 4D F4 8B 7E 73 8C D6 E9 4C 26 -[2026-02-20T18:04:35.919723] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:04:36.764262] LOG: [GPS SERVICE] Position stream fired: lat=47.35385, lon=-122.21171, accuracy=3.8m -[2026-02-20T18:04:37.574111] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:04:37.574207] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:04:37.602614] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:37.754732] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2d 09 00 00 00 79 23 00 00 -[2026-02-20T18:04:37.754876] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:37.754895] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:41.755836] LOG: [GPS SERVICE] Position stream fired: lat=47.35396, lon=-122.21002, accuracy=3.8m -[2026-02-20T18:04:42.602774] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:42.684276] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 2d 09 00 00 00 79 23 00 00 -[2026-02-20T18:04:42.684345] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:42.684354] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:04:44.161005] LOG: [CONN] Frame received (68 bytes): 88 2f c8 15 3b 32 75 4f a6 50 20 f1 f4 e3 53 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 66 97 50 7e 64 91 f0 a5 7a cd a4 c9 bb d7 26 56 93 23 46 56 9a a1 0a 43 7e 2a dd cc ca c2 eb 8d -[2026-02-20T18:04:44.161151] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:44.161182] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:44.161252] LOG: [RX PARSE] RAW Packet (65 bytes): 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D -[2026-02-20T18:04:44.161273] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:44.161284] LOG: [RX PARSE] Path length offset: 1, Path length: 59 -[2026-02-20T18:04:44.161315] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=59, firstHop=0x32, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=4 bytes -[2026-02-20T18:04:44.161333] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=59 -[2026-02-20T18:04:44.161344] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:44.161358] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:44.161419] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:44.161445] LOG: [RX FILTER] Raw packet (65 bytes): 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D -[2026-02-20T18:04:44.161462] LOG: [RX FILTER] Header: 0x15 | PathLength: 59 | SNR: 11.75 -[2026-02-20T18:04:44.161483] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:04:44.161495] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:44.161506] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:44.161522] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:44.161536] LOG: [RX FILTER] Encrypted message: 1 bytes -[2026-02-20T18:04:44.161547] LOG: [CRYPTO] Decrypting message (1 bytes) -[2026-02-20T18:04:44.161693] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:44.161743] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:44.161979] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:04:44.162091] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:04:44.162104] LOG: [RX LOG] Dropped packet hex: 15 3B 32 75 4F A6 50 20 F1 F4 E3 53 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 66 97 50 7E 64 91 F0 A5 7A CD A4 C9 BB D7 26 56 93 23 46 56 9A A1 0A 43 7E 2A DD CC CA C2 EB 8D -[2026-02-20T18:04:46.754008] LOG: [GPS SERVICE] Position stream fired: lat=47.35419, lon=-122.20829, accuracy=3.8m -[2026-02-20T18:04:46.981717] LOG: [CONN] Frame received (45 bytes): 88 30 c7 15 05 5d fb 7e dd cc ca 13 eb b4 d1 24 46 e1 66 8a 6d 05 3d f4 14 58 ab ee d0 d3 6a 12 90 04 6d 23 89 7c 88 f5 3f 65 7d 6d 6b -[2026-02-20T18:04:46.981811] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:46.981830] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:46.981856] LOG: [RX PARSE] RAW Packet (42 bytes): 15 05 5D FB 7E DD CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D 23 89 7C 88 F5 3F 65 7D 6D 6B -[2026-02-20T18:04:46.981866] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:46.981872] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:04:46.981887] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x5d, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=35 bytes -[2026-02-20T18:04:46.981894] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T18:04:46.981902] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:46.981909] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:46.981932] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:46.981940] LOG: [RX FILTER] Raw packet (42 bytes): 15 05 5D FB 7E DD CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D 23 89 7C 88 F5 3F 65 7D 6D 6B -[2026-02-20T18:04:46.981948] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 -[2026-02-20T18:04:46.981956] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:04:46.981965] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:46.981970] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:46.981976] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:46.981986] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:04:46.981991] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:04:46.982032] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:04:46.982168] LOG: [RX FILTER] Decrypted message (17 chars): "AlanHelTxt : T" -[2026-02-20T18:04:46.982181] LOG: [RX FILTER] Printable ratio: 88.2% (threshold: 60.0%) -[2026-02-20T18:04:46.982190] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:04:46.982208] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=5 -[2026-02-20T18:04:46.982215] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:04:46.982224] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 -[2026-02-20T18:04:46.982241] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:04:46.982250] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:04:46.982263] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.35419,-122.20829 -[2026-02-20T18:04:46.982272] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:04:46.982285] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35419,-122.20829 (batch tracking: 1 repeaters, rxCount: 15) -[2026-02-20T18:04:46.982297] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:04:46.982309] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.35419,-122.20829 -[2026-02-20T18:04:47.604857] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:47.772328] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 79 23 00 00 -[2026-02-20T18:04:47.772463] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:47.772480] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:51.764452] LOG: [GPS SERVICE] Position stream fired: lat=47.35461, lon=-122.20671, accuracy=3.8m -[2026-02-20T18:04:51.764503] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:04:51.764513] LOG: [RX BATCH] Distance check for repeater CC: 128.27m from first observation (threshold=25m) -[2026-02-20T18:04:51.764518] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:04:51.764521] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:04:51.764526] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:04:51.764533] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.35419,-122.20829 -[2026-02-20T18:04:51.764536] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:04:51.764542] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.35419,-122.20829 -[2026-02-20T18:04:51.764548] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 -[2026-02-20T18:04:51.764553] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:04:51.764559] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=5 -[2026-02-20T18:04:51.764620] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:04:51.764623] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:04:52.573750] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:04:52.574003] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:04:52.574021] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:04:52.575378] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:04:52.602816] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:52.782380] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 09 00 00 00 79 23 00 00 -[2026-02-20T18:04:52.782432] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:52.782442] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:53.010493] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:04:53.010609] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:04:53.010627] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639792} -[2026-02-20T18:04:53.010651] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:04:53.010670] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:04:53.013822] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:04:53.013846] LOG: [APP] Upload success: +1 items (total: 23) -[2026-02-20T18:04:54.862925] LOG: [CONN] Frame received (49 bytes): 88 30 c5 15 13 5d fb 7e 75 20 20 20 20 20 20 20 20 20 20 20 53 7e 2a cc ca 13 eb b4 d1 24 46 e1 66 8a 6d 05 3d f4 14 58 ab ee d0 d3 6a 12 90 04 6d -[2026-02-20T18:04:54.863106] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:54.863136] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:54.863193] LOG: [RX PARSE] RAW Packet (46 bytes): 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D -[2026-02-20T18:04:54.863208] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:54.863219] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:04:54.863247] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x5d, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=25 bytes -[2026-02-20T18:04:54.863261] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:04:54.863278] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:54.863287] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:54.863331] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:54.863348] LOG: [RX FILTER] Raw packet (46 bytes): 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D -[2026-02-20T18:04:54.863365] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.0 -[2026-02-20T18:04:54.863393] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:04:54.863405] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:54.863415] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:54.863432] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:54.863445] LOG: [RX FILTER] Encrypted message: 22 bytes -[2026-02-20T18:04:54.863455] LOG: [CRYPTO] Decrypting message (22 bytes) -[2026-02-20T18:04:54.863611] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:54.863659] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:04:54.863889] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:04:54.863982] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:04:54.863998] LOG: [RX LOG] Dropped packet hex: 15 13 5D FB 7E 75 20 20 20 20 20 20 20 20 20 20 20 53 7E 2A CC CA 13 EB B4 D1 24 46 E1 66 8A 6D 05 3D F4 14 58 AB EE D0 D3 6A 12 90 04 6D -[2026-02-20T18:04:55.560794] LOG: [CONN] Frame received (140 bytes): 88 32 c7 15 04 7a 7e dd cc ca 27 34 c4 62 6b 43 33 d8 d1 b0 ea 45 d6 85 7b d7 47 3c 80 81 ae 33 e3 d3 27 eb 9b 39 b0 a7 cb ea 24 28 d6 fc 20 75 98 4b 87 7c df 0c 01 a8 42 49 ec f2 39 11 a7 32 ba ef 75 31 87 48 8c 62 9a 57 59 32 e9 48 93 22 e4 83 0c 2b 8d c0 c9 df 2b 1b ad f7 b7 32 c3 30 75 b8 a5 72 fc 23 4f fd 61 55 37 cc 2b f2 17 85 da 8c 9c 9e a9 75 17 2b 2c 50 b0 fc 18 47 d7 4d 3c a1 d2 df 62 36 5f 7d 5d 13 1f ce -[2026-02-20T18:04:55.560894] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:55.560911] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:55.560992] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 7A 7E DD CC CA 27 34 C4 62 6B 43 33 D8 D1 B0 EA 45 D6 85 7B D7 47 3C 80 81 AE 33 E3 D3 27 EB 9B 39 B0 A7 CB EA 24 28 D6 FC 20 75 98 4B 87 7C DF 0C 01 A8 42 49 EC F2 39 11 A7 32 BA EF 75 31 87 48 8C 62 9A 57 59 32 E9 48 93 22 E4 83 0C 2B 8D C0 C9 DF 2B 1B AD F7 B7 32 C3 30 75 B8 A5 72 FC 23 4F FD 61 55 37 CC 2B F2 17 85 DA 8C 9C 9E A9 75 17 2B 2C 50 B0 FC 18 47 D7 4D 3C A1 D2 DF 62 36 5F 7D 5D 13 1F CE -[2026-02-20T18:04:55.561004] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:55.561011] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:04:55.561029] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x7a, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=131 bytes -[2026-02-20T18:04:55.561041] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:04:55.561045] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:55.561053] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:55.561106] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:04:55.561114] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 7A 7E DD CC CA 27 34 C4 62 6B 43 33 D8 D1 B0 EA 45 D6 85 7B D7 47 3C 80 81 AE 33 E3 D3 27 EB 9B 39 B0 A7 CB EA 24 28 D6 FC 20 75 98 4B 87 7C DF 0C 01 A8 42 49 EC F2 39 11 A7 32 BA EF 75 31 87 48 8C 62 9A 57 59 32 E9 48 93 22 E4 83 0C 2B 8D C0 C9 DF 2B 1B AD F7 B7 32 C3 30 75 B8 A5 72 FC 23 4F FD 61 55 37 CC 2B F2 17 85 DA 8C 9C 9E A9 75 17 2B 2C 50 B0 FC 18 47 D7 4D 3C A1 D2 DF 62 36 5F 7D 5D 13 1F CE -[2026-02-20T18:04:55.561125] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.5 -[2026-02-20T18:04:55.561135] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:04:55.561141] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:04:55.561148] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:04:55.561155] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:04:55.561160] LOG: [RX FILTER] Encrypted message: 128 bytes -[2026-02-20T18:04:55.561167] LOG: [CRYPTO] Decrypting message (128 bytes) -[2026-02-20T18:04:55.561226] LOG: [CRYPTO] Decrypted successfully (128 bytes) -[2026-02-20T18:04:55.561332] LOG: [RX FILTER] Decrypted message (115 chars): "HowlBot: ack @[AlanHelTxt ] | 5d,1f,7a | Path Dist: 69.1km ..." -[2026-02-20T18:04:55.561347] LOG: [RX FILTER] Printable ratio: 96.5% (threshold: 60.0%) -[2026-02-20T18:04:55.561351] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:04:55.561370] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=4 -[2026-02-20T18:04:55.561374] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:04:55.561385] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:04:55.561394] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:04:55.561407] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:04:55.561419] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35461,-122.20671 -[2026-02-20T18:04:55.561428] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:04:55.561444] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35461,-122.20671 (batch tracking: 1 repeaters, rxCount: 16) -[2026-02-20T18:04:55.561456] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:04:55.561466] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35461,-122.20671 -[2026-02-20T18:04:55.660922] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:04:55.661060] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:04:55.661078] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:04:55.661117] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:04:55.661161] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35461, -122.20671 [0.3w]" -[2026-02-20T18:04:55.661173] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:04:55.661188] LOG: [TX LOG] Payload: "@[MapperBot] 47.35461, -122.20671 [0.3w]" -[2026-02-20T18:04:55.661202] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:04:55.661219] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:04:55.661231] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:04:55.661242] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:04:55.661267] LOG: [CONN] Sending ping: @[MapperBot] 47.35461, -122.20671 [0.3w] -[2026-02-20T18:04:55.753448] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:04:55.753577] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:04:55.753590] LOG: [CONN] Received OK response -[2026-02-20T18:04:57.077270] LOG: [GPS SERVICE] Position stream fired: lat=47.35513, lon=-122.20508, accuracy=4.5m -[2026-02-20T18:04:57.077350] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:04:57.077380] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:04:57.077394] LOG: [RX BATCH] Distance check for repeater CC: 135.79m from first observation (threshold=25m) -[2026-02-20T18:04:57.077399] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:04:57.077404] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:04:57.077413] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:04:57.077421] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35461,-122.20671 -[2026-02-20T18:04:57.077429] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:04:57.077434] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35461,-122.20671 -[2026-02-20T18:04:57.077441] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:04:57.077449] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:04:57.077457] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=4 -[2026-02-20T18:04:57.077529] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:04:57.077555] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:04:57.077563] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:04:57.387811] LOG: [CONN] Frame received (73 bytes): 88 30 c7 15 01 cc 81 83 65 93 67 92 c2 fc 2f 19 91 1a 48 d5 30 a4 30 b9 be b0 1c b7 24 8a 2e ea 47 03 36 7d 92 f1 1b 20 8c 65 f1 6a 5a 7a c0 1b 30 12 bb c7 b2 dc ce f1 07 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:04:57.387842] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:04:57.387850] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:04:57.387862] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 83 65 93 67 92 C2 FC 2F 19 91 1A 48 D5 30 A4 30 B9 BE B0 1C B7 24 8A 2E EA 47 03 36 7D 92 F1 1B 20 8C 65 F1 6A 5A 7A C0 1B 30 12 BB C7 B2 DC CE F1 07 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:04:57.387865] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:04:57.387867] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:04:57.387872] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=67 bytes -[2026-02-20T18:04:57.387875] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:04:57.387877] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:04:57.387879] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-57 -[2026-02-20T18:04:57.387881] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:04:57.387883] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:04:57.387885] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:04:57.387887] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:04:57.387889] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:04:57.602812] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:04:57.602952] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:04:57.735610] LOG: [CONN] Frame received (11 bytes): 0c d7 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:04:57.735730] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:04:57.735744] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:04:57.735760] LOG: [CONN] Battery updated: 4055mV (88%) -[2026-02-20T18:04:57.792159] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 -[2026-02-20T18:04:57.792219] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:04:57.792229] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:04:58.015850] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:04:58.756562] LOG: [PING] Ping sent successfully -[2026-02-20T18:05:00.662089] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:05:01.744556] LOG: [GPS SERVICE] Position stream fired: lat=47.35547, lon=-122.20365, accuracy=5.0m -[2026-02-20T18:05:02.602841] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:02.684550] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 -[2026-02-20T18:05:02.684622] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:02.684635] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:03.757836] LOG: [PING] RX listening window ended -[2026-02-20T18:05:03.757964] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:05:03.757991] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:05:03.758057] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:05:03.758077] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:05:03.758092] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:05:03.758120] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:05:03.758136] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:05:03.758585] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:05:06.736170] LOG: [GPS SERVICE] Position stream fired: lat=47.35568, lon=-122.20199, accuracy=5.4m -[2026-02-20T18:05:07.573759] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:05:07.574007] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:05:07.574023] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:05:07.574033] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:05:07.577075] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:05:07.602609] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:07.691038] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 -[2026-02-20T18:05:07.691098] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:07.691105] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:08.126024] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:05:08.126077] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:05:08.126087] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771639807} -[2026-02-20T18:05:08.126099] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:05:08.126108] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:05:08.126720] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:05:08.126732] LOG: [APP] Upload success: +2 items (total: 25) -[2026-02-20T18:05:08.759853] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:05:08.759978] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:05:12.079249] LOG: [GPS SERVICE] Position stream fired: lat=47.35575, lon=-122.20030, accuracy=7.0m -[2026-02-20T18:05:12.604025] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:12.704116] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 -[2026-02-20T18:05:12.704202] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:12.704215] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:13.127633] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:05:16.740522] LOG: [GPS SERVICE] Position stream fired: lat=47.35580, lon=-122.19880, accuracy=5.8m -[2026-02-20T18:05:17.603047] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:17.714785] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 30 0a 00 00 00 7a 23 00 00 -[2026-02-20T18:05:17.714885] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:17.714900] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:18.050653] LOG: [CONN] Frame received (47 bytes): 88 2f c7 09 06 87 f7 c7 7e 1b cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 36 71 06 99 23 04 c6 3b 7d 4f af -[2026-02-20T18:05:18.050843] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:18.050876] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:18.050928] LOG: [RX PARSE] RAW Packet (44 bytes): 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF -[2026-02-20T18:05:18.050949] LOG: [RX PARSE] Header: 0x09, Route type: 1 -[2026-02-20T18:05:18.050961] LOG: [RX PARSE] Path length offset: 1, Path length: 6 -[2026-02-20T18:05:18.050992] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=6, firstHop=0x87, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=36 bytes -[2026-02-20T18:05:18.051006] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=6 -[2026-02-20T18:05:18.051024] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:18.051037] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:18.051087] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:18.051170] LOG: [RX FILTER] Raw packet (44 bytes): 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF -[2026-02-20T18:05:18.051188] LOG: [RX FILTER] Header: 0x09 | PathLength: 6 | SNR: 11.75 -[2026-02-20T18:05:18.051213] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:05:18.051231] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) -[2026-02-20T18:05:18.051288] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:05:18.051300] LOG: [RX LOG] Dropped packet hex: 09 06 87 F7 C7 7E 1B CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 C6 3B 7D 4F AF -[2026-02-20T18:05:21.030305] LOG: [CONN] Frame received (81 bytes): 88 32 c6 15 09 8b 1c ab 5a 53 7e e8 32 cc 81 8c 3d 6c b4 48 5f 14 79 87 9e 99 b0 de dc e8 a3 25 fe 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 f7 23 4d 7a f9 6c ff 26 80 e4 6f 42 ef b1 e4 b5 eb fd 9b 57 27 bc 53 60 10 db 82 15 f7 04 5b c9 -[2026-02-20T18:05:21.030480] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:21.030663] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:21.030726] LOG: [RX PARSE] RAW Packet (78 bytes): 15 09 8B 1C AB 5A 53 7E E8 32 CC 81 8C 3D 6C B4 48 5F 14 79 87 9E 99 B0 DE DC E8 A3 25 FE 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 F7 23 4D 7A F9 6C FF 26 80 E4 6F 42 EF B1 E4 B5 EB FD 9B 57 27 BC 53 60 10 DB 82 15 F7 04 5B C9 -[2026-02-20T18:05:21.030742] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:05:21.030752] LOG: [RX PARSE] Path length offset: 1, Path length: 9 -[2026-02-20T18:05:21.030770] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0x8b, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes -[2026-02-20T18:05:21.030785] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 -[2026-02-20T18:05:21.030793] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:21.030804] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:21.030863] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:21.030872] LOG: [RX FILTER] Raw packet (78 bytes): 15 09 8B 1C AB 5A 53 7E E8 32 CC 81 8C 3D 6C B4 48 5F 14 79 87 9E 99 B0 DE DC E8 A3 25 FE 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 F7 23 4D 7A F9 6C FF 26 80 E4 6F 42 EF B1 E4 B5 EB FD 9B 57 27 BC 53 60 10 DB 82 15 F7 04 5B C9 -[2026-02-20T18:05:21.030890] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 12.5 -[2026-02-20T18:05:21.030902] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:05:21.030910] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:05:21.030924] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:05:21.030934] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:05:21.030947] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:05:21.030959] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:05:21.031032] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:05:21.031176] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.97623, -123.80079 [0.3w]" -[2026-02-20T18:05:21.031197] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:05:21.031211] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:05:21.031236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=9 -[2026-02-20T18:05:21.031247] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:05:21.031270] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:05:21.031284] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:05:21.031299] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:05:21.031319] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35580,-122.19880 -[2026-02-20T18:05:21.031334] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:05:21.031355] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35580,-122.19880 (batch tracking: 1 repeaters, rxCount: 17) -[2026-02-20T18:05:21.031372] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:05:21.031391] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35580,-122.19880 -[2026-02-20T18:05:21.031726] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:05:21.031740] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:05:21.031750] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:05:21.775839] LOG: [GPS SERVICE] Position stream fired: lat=47.35589, lon=-122.19731, accuracy=5.3m -[2026-02-20T18:05:21.775872] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:05:21.775883] LOG: [RX BATCH] Distance check for repeater CC: 113.30m from first observation (threshold=25m) -[2026-02-20T18:05:21.775886] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:05:21.775890] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:05:21.775894] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:05:21.775898] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35580,-122.19880 -[2026-02-20T18:05:21.775902] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:05:21.775905] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35580,-122.19880 -[2026-02-20T18:05:21.775913] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:05:21.775917] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:05:21.775921] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=9 -[2026-02-20T18:05:21.775971] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:05:21.775974] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:05:22.575161] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:05:22.575434] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:05:22.575455] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:05:22.576674] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:05:22.578281] LOG: [CONN] Frame received (50 bytes): 88 30 c6 09 0e 87 f7 c7 7e 75 20 20 20 20 20 20 53 7e cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 36 71 06 99 23 04 -[2026-02-20T18:05:22.578308] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:22.578337] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:22.578390] LOG: [RX PARSE] RAW Packet (47 bytes): 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 -[2026-02-20T18:05:22.578405] LOG: [RX PARSE] Header: 0x09, Route type: 1 -[2026-02-20T18:05:22.578422] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:05:22.578446] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=14, firstHop=0x87, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=31 bytes -[2026-02-20T18:05:22.578465] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=14 -[2026-02-20T18:05:22.578477] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:22.578486] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:22.578611] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:22.578632] LOG: [RX FILTER] Raw packet (47 bytes): 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 -[2026-02-20T18:05:22.578648] LOG: [RX FILTER] Header: 0x09 | PathLength: 14 | SNR: 12.0 -[2026-02-20T18:05:22.578668] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:05:22.578682] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) -[2026-02-20T18:05:22.578762] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:05:22.578769] LOG: [RX LOG] Dropped packet hex: 09 0E 87 F7 C7 7E 75 20 20 20 20 20 20 53 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 36 71 06 99 23 04 -[2026-02-20T18:05:22.602581] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:22.781818] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 30 0a 00 00 00 7b 23 00 00 -[2026-02-20T18:05:22.781895] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:22.781905] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:23.031108] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:05:23.031147] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:05:23.031154] LOG: [API] Response (200) in 0.46s: {"success":true,"expires_at":1771639822} -[2026-02-20T18:05:23.031164] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:05:23.031171] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:05:23.031352] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:05:23.031360] LOG: [APP] Upload success: +1 items (total: 26) -[2026-02-20T18:05:26.775390] LOG: [GPS SERVICE] Position stream fired: lat=47.35595, lon=-122.19594, accuracy=4.8m -[2026-02-20T18:05:27.602845] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:05:27.603125] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:27.644525] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:05:27.644611] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:05:27.644622] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:05:27.644631] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T18:05:27.703883] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 30 0a 00 00 00 7b 23 00 00 -[2026-02-20T18:05:27.704023] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:27.704050] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:05:28.031900] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:05:29.991106] LOG: [CONN] Frame received (60 bytes): 88 2f c6 09 18 87 f7 c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 c5 75 7e cc d2 3f b0 0b 6d ab 1b 18 59 53 7e 66 c2 58 e6 ed 4c 04 18 1f f6 70 81 73 01 99 23 04 c6 3b 7d -[2026-02-20T18:05:29.991263] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:29.991301] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:29.991360] LOG: [RX PARSE] RAW Packet (57 bytes): 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D -[2026-02-20T18:05:29.991380] LOG: [RX PARSE] Header: 0x09, Route type: 1 -[2026-02-20T18:05:29.991392] LOG: [RX PARSE] Path length offset: 1, Path length: 24 -[2026-02-20T18:05:29.991428] LOG: [RX PARSE] Parsed metadata: header=0x09, pathLength=24, firstHop=0x87, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=31 bytes -[2026-02-20T18:05:29.991442] LOG: [UNIFIED RX] Packet received: header=0x9, pathLength=24 -[2026-02-20T18:05:29.991458] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:29.991469] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:29.991535] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:29.991546] LOG: [RX FILTER] Raw packet (57 bytes): 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D -[2026-02-20T18:05:29.991567] LOG: [RX FILTER] Header: 0x09 | PathLength: 24 | SNR: 11.75 -[2026-02-20T18:05:29.991582] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:05:29.991594] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x09) -[2026-02-20T18:05:29.991660] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:05:29.991676] LOG: [RX LOG] Dropped packet hex: 09 18 87 F7 C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 C5 75 7E CC D2 3F B0 0B 6D AB 1B 18 59 53 7E 66 C2 58 E6 ED 4C 04 18 1F F6 70 81 73 01 99 23 04 C6 3B 7D -[2026-02-20T18:05:31.768349] LOG: [GPS SERVICE] Position stream fired: lat=47.35602, lon=-122.19456, accuracy=4.7m -[2026-02-20T18:05:31.768379] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:05:31.768424] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:05:32.602596] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:32.745912] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 0a 00 00 00 7b 23 00 00 -[2026-02-20T18:05:32.746034] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:32.746054] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:33.758657] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:05:33.758767] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:05:33.758776] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:05:33.758790] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:05:33.758806] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35602, -122.19456 [0.3w]" -[2026-02-20T18:05:33.758808] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:05:33.758810] LOG: [TX LOG] Payload: "@[MapperBot] 47.35602, -122.19456 [0.3w]" -[2026-02-20T18:05:33.758815] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:05:33.758818] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:05:33.758821] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:05:33.758824] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:05:33.758829] LOG: [CONN] Sending ping: @[MapperBot] 47.35602, -122.19456 [0.3w] -[2026-02-20T18:05:33.851034] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:05:33.851090] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:05:33.851095] LOG: [CONN] Received OK response -[2026-02-20T18:05:35.418001] LOG: [CONN] Frame received (73 bytes): 88 32 c8 15 01 cc 81 00 58 4c 82 6a 20 fb 92 79 99 d0 7b e3 72 e3 14 55 b2 b3 02 e5 1b 24 67 87 c6 11 ea f7 80 a4 37 68 d8 99 86 c1 7b fb 90 9b a7 e8 90 59 2b 36 50 bb 74 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:05:35.418160] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:35.418191] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:35.418262] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 00 58 4C 82 6A 20 FB 92 79 99 D0 7B E3 72 E3 14 55 B2 B3 02 E5 1B 24 67 87 C6 11 EA F7 80 A4 37 68 D8 99 86 C1 7B FB 90 9B A7 E8 90 59 2B 36 50 BB 74 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:05:35.418283] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:05:35.418296] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:05:35.418317] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=67 bytes -[2026-02-20T18:05:35.418336] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:05:35.418346] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:05:35.418362] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-56 -[2026-02-20T18:05:35.418375] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:05:35.418385] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:05:35.418402] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:35.418411] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:35.418421] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:05:36.752127] LOG: [GPS SERVICE] Position stream fired: lat=47.35606, lon=-122.19321, accuracy=4.6m -[2026-02-20T18:05:36.858432] LOG: [PING] Ping sent successfully -[2026-02-20T18:05:37.573713] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:05:37.573886] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:05:37.605362] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:37.723117] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 0a 00 00 00 7b 23 00 00 -[2026-02-20T18:05:37.723261] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:37.723280] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:38.762001] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:05:41.770972] LOG: [GPS SERVICE] Position stream fired: lat=47.35613, lon=-122.19188, accuracy=3.8m -[2026-02-20T18:05:41.861682] LOG: [PING] RX listening window ended -[2026-02-20T18:05:41.861860] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:05:41.861893] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:05:41.861999] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:05:41.862021] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:05:41.862036] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:05:41.862070] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:05:41.862096] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:05:41.863379] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:05:42.450438] LOG: [CONN] Frame received (69 bytes): 88 2f c7 15 0f c6 38 a9 c5 75 20 20 20 75 2b f4 f1 20 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d -[2026-02-20T18:05:42.450651] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:42.450698] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:42.450765] LOG: [RX PARSE] RAW Packet (66 bytes): 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D -[2026-02-20T18:05:42.450788] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:05:42.450801] LOG: [RX PARSE] Path length offset: 1, Path length: 15 -[2026-02-20T18:05:42.450833] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0xc6, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=49 bytes -[2026-02-20T18:05:42.450847] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 -[2026-02-20T18:05:42.450863] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:42.450875] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:42.450942] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:42.450953] LOG: [RX FILTER] Raw packet (66 bytes): 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D -[2026-02-20T18:05:42.450976] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 11.75 -[2026-02-20T18:05:42.450991] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:05:42.451007] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:05:42.451021] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:05:42.451033] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:05:42.451123] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:05:42.451136] LOG: [RX LOG] Dropped packet hex: 15 0F C6 38 A9 C5 75 20 20 20 75 2B F4 F1 20 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D -[2026-02-20T18:05:42.603161] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:42.791630] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2f 0a 00 00 00 7c 23 00 00 -[2026-02-20T18:05:42.791708] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:42.791718] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:46.770604] LOG: [GPS SERVICE] Position stream fired: lat=47.35618, lon=-122.19050, accuracy=3.8m -[2026-02-20T18:05:46.866557] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:05:46.866703] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:05:46.866714] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:05:47.302996] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:05:47.303089] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:05:47.303104] LOG: [API] Response (200) in 0.44s: {"success":true,"expires_at":1771639847} -[2026-02-20T18:05:47.303121] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:05:47.303134] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:05:47.303468] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:05:47.303483] LOG: [APP] Upload success: +1 items (total: 27) -[2026-02-20T18:05:47.602806] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:47.653275] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2f 0a 00 00 00 7c 23 00 00 -[2026-02-20T18:05:47.653399] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:47.653418] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:49.110087] LOG: [CONN] Frame received (67 bytes): 88 33 c8 15 15 c6 38 a9 c5 75 20 20 20 20 20 20 20 20 20 20 20 75 f7 53 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e -[2026-02-20T18:05:49.110212] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:49.110241] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:49.110289] LOG: [RX PARSE] RAW Packet (64 bytes): 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E -[2026-02-20T18:05:49.110305] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:05:49.110314] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:05:49.110342] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xc6, lastHop=0xcc, SNR=12.75, RSSI=-56, payload=41 bytes -[2026-02-20T18:05:49.110353] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:05:49.110366] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:49.110376] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:49.110431] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:49.110439] LOG: [RX FILTER] Raw packet (64 bytes): 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E -[2026-02-20T18:05:49.110456] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.75 -[2026-02-20T18:05:49.110468] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:05:49.110476] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:05:49.110489] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:05:49.110497] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:05:49.110693] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:05:49.110712] LOG: [RX LOG] Dropped packet hex: 15 15 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 75 F7 53 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E -[2026-02-20T18:05:51.769968] LOG: [GPS SERVICE] Position stream fired: lat=47.35641, lon=-122.18916, accuracy=3.8m -[2026-02-20T18:05:52.303710] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:05:52.573549] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:05:52.573575] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:05:52.603001] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:52.755852] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 33 0a 00 00 00 7c 23 00 00 -[2026-02-20T18:05:52.756006] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:52.756025] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:05:56.190657] LOG: [CONN] Frame received (65 bytes): 88 31 c8 15 20 c6 38 a9 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e cc 23 97 6a 8e 4c e2 12 f8 ef 1b 68 0e c3 64 e9 ab bd 1b 56 67 6b 33 3a dd 84 c5 c5 b5 -[2026-02-20T18:05:56.190830] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:05:56.190864] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:05:56.190934] LOG: [RX PARSE] RAW Packet (62 bytes): 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 -[2026-02-20T18:05:56.190954] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:05:56.190965] LOG: [RX PARSE] Path length offset: 1, Path length: 32 -[2026-02-20T18:05:56.190996] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=32, firstHop=0xc6, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=28 bytes -[2026-02-20T18:05:56.191010] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=32 -[2026-02-20T18:05:56.191025] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:05:56.191037] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:05:56.191092] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:05:56.191108] LOG: [RX FILTER] Raw packet (62 bytes): 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 -[2026-02-20T18:05:56.191125] LOG: [RX FILTER] Header: 0x15 | PathLength: 32 | SNR: 12.25 -[2026-02-20T18:05:56.191144] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:05:56.191155] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:05:56.191165] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:05:56.191180] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:05:56.191247] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:05:56.191259] LOG: [RX LOG] Dropped packet hex: 15 20 C6 38 A9 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E CC 23 97 6A 8E 4C E2 12 F8 EF 1B 68 0E C3 64 E9 AB BD 1B 56 67 6B 33 3A DD 84 C5 C5 B5 -[2026-02-20T18:05:56.783465] LOG: [GPS SERVICE] Position stream fired: lat=47.35692, lon=-122.18801, accuracy=3.8m -[2026-02-20T18:05:57.604990] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:05:57.605190] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:05:57.733360] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:05:57.733504] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:05:57.733523] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:05:57.733538] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:05:57.798017] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 31 0a 00 00 00 7c 23 00 00 -[2026-02-20T18:05:57.798146] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:05:57.798167] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:02.080600] LOG: [GPS SERVICE] Position stream fired: lat=47.35772, lon=-122.18715, accuracy=3.8m -[2026-02-20T18:06:02.080637] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:06:02.080691] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:06:02.603041] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:02.653240] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 31 0a 00 00 00 7c 23 00 00 -[2026-02-20T18:06:02.653371] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:02.653392] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:02.897370] LOG: [CONN] Frame received (61 bytes): 88 30 c8 15 05 24 6c db 9b cc 23 12 8c 0b d3 15 1a 15 c8 32 e7 b2 31 ba c4 c9 dc 7e 0a 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d f2 ea -[2026-02-20T18:06:02.897456] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:02.897482] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:02.897537] LOG: [RX PARSE] RAW Packet (58 bytes): 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA -[2026-02-20T18:06:02.897549] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:02.897560] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:06:02.897577] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0x24, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=51 bytes -[2026-02-20T18:06:02.897591] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T18:06:02.897600] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:02.897607] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:02.897651] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:02.897660] LOG: [RX FILTER] Raw packet (58 bytes): 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA -[2026-02-20T18:06:02.897676] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 12.0 -[2026-02-20T18:06:02.897686] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:06:02.897697] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:02.897705] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:06:02.897713] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:06:02.897825] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:06:02.897836] LOG: [RX LOG] Dropped packet hex: 15 05 24 6C DB 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 EA -[2026-02-20T18:06:06.420044] LOG: [CONN] Frame received (63 bytes): 88 2f c7 15 07 24 6c 5d 54 1f 9b cc 23 12 8c 0b d3 15 1a 15 c8 32 e7 b2 31 ba c4 c9 dc 7e 0a 67 6b 33 3a dd 84 c5 c5 b5 4e 8e 76 e1 6b 3b e3 ce 05 8e d4 4e 1e 52 4c 41 dc f8 da 0e 3d f2 e9 -[2026-02-20T18:06:06.420096] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:06.420133] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:06.420195] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 -[2026-02-20T18:06:06.420213] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:06.420224] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:06:06.420305] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x24, lastHop=0xcc, SNR=11.75, RSSI=-57, payload=51 bytes -[2026-02-20T18:06:06.420320] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:06:06.420337] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:06.420346] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:06.420472] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:06.420485] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 -[2026-02-20T18:06:06.420507] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.75 -[2026-02-20T18:06:06.420521] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:06:06.420536] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:06.420547] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:06:06.420557] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:06:06.420718] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:06:06.420732] LOG: [RX LOG] Dropped packet hex: 15 07 24 6C 5D 54 1F 9B CC 23 12 8C 0B D3 15 1A 15 C8 32 E7 B2 31 BA C4 C9 DC 7E 0A 67 6B 33 3A DD 84 C5 C5 B5 4E 8E 76 E1 6B 3B E3 CE 05 8E D4 4E 1E 52 4C 41 DC F8 DA 0E 3D F2 E9 -[2026-02-20T18:06:06.744878] LOG: [GPS SERVICE] Position stream fired: lat=47.35859, lon=-122.18674, accuracy=3.8m -[2026-02-20T18:06:07.169875] LOG: [CONN] Frame received (83 bytes): 88 32 c8 15 0b 32 8b 85 28 aa 50 5a 15 7a 7e cc 81 82 a2 42 1d 31 e6 2f 8d 46 05 d6 6c 67 6e 30 b5 25 6a 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 1b 10 d0 d6 d3 ea 68 e4 2e f2 e6 cd 70 03 fd f8 39 b6 0d 55 8a 76 73 42 63 8d ac 80 3f c7 96 ac -[2026-02-20T18:06:07.170002] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:07.170023] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:07.170065] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 32 8B 85 28 AA 50 5A 15 7A 7E CC 81 82 A2 42 1D 31 E6 2F 8D 46 05 D6 6C 67 6E 30 B5 25 6A 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 1B 10 D0 D6 D3 EA 68 E4 2E F2 E6 CD 70 03 FD F8 39 B6 0D 55 8A 76 73 42 63 8D AC 80 3F C7 96 AC -[2026-02-20T18:06:07.170075] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:07.170085] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:06:07.170107] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x32, lastHop=0xcc, SNR=12.5, RSSI=-56, payload=67 bytes -[2026-02-20T18:06:07.170117] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:06:07.170124] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:07.170129] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:07.170166] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:07.170173] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 32 8B 85 28 AA 50 5A 15 7A 7E CC 81 82 A2 42 1D 31 E6 2F 8D 46 05 D6 6C 67 6E 30 B5 25 6A 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 1B 10 D0 D6 D3 EA 68 E4 2E F2 E6 CD 70 03 FD F8 39 B6 0D 55 8A 76 73 42 63 8D AC 80 3F C7 96 AC -[2026-02-20T18:06:07.170187] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 -[2026-02-20T18:06:07.170194] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:06:07.170199] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:07.170208] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:07.170214] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:07.170223] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:06:07.170232] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:06:07.170279] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:06:07.170645] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.98584, -123.80795 [0.3w]" -[2026-02-20T18:06:07.170657] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:06:07.170667] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:06:07.170685] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=11 -[2026-02-20T18:06:07.170693] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:06:07.170704] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:06:07.170716] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:06:07.170727] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:06:07.170799] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.35859,-122.18674 -[2026-02-20T18:06:07.170820] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:06:07.170841] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35859,-122.18674 (batch tracking: 1 repeaters, rxCount: 18) -[2026-02-20T18:06:07.170855] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:06:07.170871] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.35859,-122.18674 -[2026-02-20T18:06:07.171166] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:06:07.171175] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:06:07.171183] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:06:07.574754] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:06:07.574906] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:06:07.603172] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:07.662267] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 32 0a 00 00 00 7d 23 00 00 -[2026-02-20T18:06:07.662377] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:07.662401] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:11.764446] LOG: [GPS SERVICE] Position stream fired: lat=47.35953, lon=-122.18668, accuracy=3.8m -[2026-02-20T18:06:11.764504] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:06:11.764519] LOG: [RX BATCH] Distance check for repeater CC: 104.04m from first observation (threshold=25m) -[2026-02-20T18:06:11.764523] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:06:11.764533] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:06:11.764541] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:06:11.764547] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.35859,-122.18674 -[2026-02-20T18:06:11.764554] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:06:11.764558] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.35859,-122.18674 -[2026-02-20T18:06:11.764568] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:06:11.764575] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:06:11.764580] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=11 -[2026-02-20T18:06:11.764668] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:06:11.764672] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:06:11.863208] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:06:11.863362] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:06:11.863387] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:06:11.863433] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:06:11.863483] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35953, -122.18668 [0.3w]" -[2026-02-20T18:06:11.863498] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:06:11.863508] LOG: [TX LOG] Payload: "@[MapperBot] 47.35953, -122.18668 [0.3w]" -[2026-02-20T18:06:11.863526] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:06:11.863539] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:06:11.863557] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:06:11.863571] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:06:11.863592] LOG: [CONN] Sending ping: @[MapperBot] 47.35953, -122.18668 [0.3w] -[2026-02-20T18:06:11.924559] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:06:11.924687] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:06:11.924701] LOG: [CONN] Received OK response -[2026-02-20T18:06:12.602883] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:12.736904] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 32 0a 00 00 00 7d 23 00 00 -[2026-02-20T18:06:12.737049] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:12.737069] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:13.685194] LOG: [CONN] Frame received (73 bytes): 88 2e c6 15 01 cc 81 a4 c4 03 71 4b ac 84 c9 e1 ce 7a 67 fc cc 1b 29 2a 3d 96 ec 08 7f 85 ea 67 0b ab 5d 58 eb 78 ec b7 e8 3d 7a fa 69 77 52 cb b5 e6 d9 e7 3d 59 60 eb c2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:06:13.685356] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:13.685392] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:13.685474] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A4 C4 03 71 4B AC 84 C9 E1 CE 7A 67 FC CC 1B 29 2A 3D 96 EC 08 7F 85 EA 67 0B AB 5D 58 EB 78 EC B7 E8 3D 7A FA 69 77 52 CB B5 E6 D9 E7 3D 59 60 EB C2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:06:13.685490] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:13.685501] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:06:13.685540] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-58, payload=67 bytes -[2026-02-20T18:06:13.685555] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:06:13.685571] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:06:13.685583] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-58 -[2026-02-20T18:06:13.685593] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:06:13.685608] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:06:13.685621] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:13.685637] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:13.685648] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:06:14.924996] LOG: [PING] Ping sent successfully -[2026-02-20T18:06:14.957117] LOG: [CONN] Frame received (76 bytes): 88 2f c6 15 04 15 ae 7e cc 23 f0 81 0e 18 54 5f 26 4c 9d 1a be 81 48 99 c1 80 51 2d f9 bd 90 a6 97 8c 93 fa 4f 1f fd 33 57 46 97 58 b7 ff 85 c2 18 53 10 f9 75 18 63 60 8d c9 c3 86 d2 88 2c 49 a2 25 d3 5d 1e 8a 36 44 99 ee 9e f4 -[2026-02-20T18:06:14.957213] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:14.957235] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:14.957275] LOG: [RX PARSE] RAW Packet (73 bytes): 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 -[2026-02-20T18:06:14.957283] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:14.957292] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:06:14.957307] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=67 bytes -[2026-02-20T18:06:14.957317] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:06:14.957324] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:06:14.957330] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-58 -[2026-02-20T18:06:14.957339] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:06:14.957348] LOG: [TX LOG] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:06:14.957354] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x23, expected=0x81 -[2026-02-20T18:06:14.957363] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:06:14.957369] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:14.957376] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:14.957411] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:14.957420] LOG: [RX FILTER] Raw packet (73 bytes): 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 -[2026-02-20T18:06:14.957429] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.75 -[2026-02-20T18:06:14.957438] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:06:14.957443] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:14.957451] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:06:14.957458] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:06:14.957495] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:06:14.957508] LOG: [RX LOG] Dropped packet hex: 15 04 15 AE 7E CC 23 F0 81 0E 18 54 5F 26 4C 9D 1A BE 81 48 99 C1 80 51 2D F9 BD 90 A6 97 8C 93 FA 4F 1F FD 33 57 46 97 58 B7 FF 85 C2 18 53 10 F9 75 18 63 60 8D C9 C3 86 D2 88 2C 49 A2 25 D3 5D 1E 8A 36 44 99 EE 9E F4 -[2026-02-20T18:06:16.771136] LOG: [GPS SERVICE] Position stream fired: lat=47.36043, lon=-122.18669, accuracy=3.8m -[2026-02-20T18:06:16.864607] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:06:17.603556] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:17.712483] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 2f 0a 00 00 00 7e 23 00 00 -[2026-02-20T18:06:17.712527] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:17.712533] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:19.893267] LOG: [CONN] Frame received (74 bytes): 88 31 c8 15 02 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e 3a d4 39 7c bb af 68 96 77 c1 86 ef b7 91 b3 63 -[2026-02-20T18:06:19.893415] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:19.893444] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:19.893517] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 B3 63 -[2026-02-20T18:06:19.893539] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:19.893550] LOG: [RX PARSE] Path length offset: 1, Path length: 2 -[2026-02-20T18:06:19.893576] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=67 bytes -[2026-02-20T18:06:19.893590] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 -[2026-02-20T18:06:19.893606] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:19.893617] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:19.893682] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:19.893694] LOG: [RX FILTER] Raw packet (71 bytes): 15 02 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 B3 63 -[2026-02-20T18:06:19.893717] LOG: [RX FILTER] Header: 0x15 | PathLength: 2 | SNR: 12.25 -[2026-02-20T18:06:19.893731] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:06:19.893757] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:19.893772] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:19.893784] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:19.893801] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:06:19.893817] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:06:19.893914] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:06:19.894085] LOG: [RX FILTER] Decrypted message (48 chars): "tObLiN: @[MapperBot] 47.62796, -122.15860 [0.3w]" -[2026-02-20T18:06:19.894111] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:06:19.894128] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:06:19.894160] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=2 -[2026-02-20T18:06:19.894172] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:06:19.894187] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:06:19.894209] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:06:19.894228] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:06:19.894254] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36043,-122.18669 -[2026-02-20T18:06:19.894272] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:06:19.894295] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36043,-122.18669 (batch tracking: 1 repeaters, rxCount: 19) -[2026-02-20T18:06:19.894317] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:06:19.894341] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36043,-122.18669 -[2026-02-20T18:06:19.894774] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:06:19.894782] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:06:19.894789] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:06:19.925624] LOG: [PING] RX listening window ended -[2026-02-20T18:06:19.925718] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:06:19.925728] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:06:19.925774] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:06:19.925780] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:06:19.925786] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:06:19.925796] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:06:19.925802] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:06:19.925961] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:06:21.760906] LOG: [GPS SERVICE] Position stream fired: lat=47.36133, lon=-122.18668, accuracy=3.8m -[2026-02-20T18:06:21.761002] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:06:21.761015] LOG: [RX BATCH] Distance check for repeater CC: 99.13m from first observation (threshold=25m) -[2026-02-20T18:06:21.761019] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:06:21.761025] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:06:21.761031] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:06:21.761050] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36043,-122.18669 -[2026-02-20T18:06:21.761054] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:06:21.761058] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36043,-122.18669 -[2026-02-20T18:06:21.761067] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:06:21.761074] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:06:21.761080] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=2 -[2026-02-20T18:06:21.761160] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:06:21.761164] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:06:22.573895] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:06:22.574152] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:06:22.574169] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:06:22.574178] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:06:22.575835] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue -[2026-02-20T18:06:22.603467] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:22.783375] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 31 0a 00 00 00 7e 23 00 00 -[2026-02-20T18:06:22.783497] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:22.783521] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:23.023200] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:06:23.023227] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:06:23.023231] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771639882} -[2026-02-20T18:06:23.023237] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:06:23.023242] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:06:23.023452] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:06:23.023456] LOG: [APP] Upload success: +2 items (total: 29) -[2026-02-20T18:06:24.926744] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:06:24.926863] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:06:24.926870] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:06:25.171880] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:06:25.171993] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:06:25.172010] LOG: [API] Response (200) in 0.24s: {"success":true,"expires_at":1771639885} -[2026-02-20T18:06:25.172034] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:06:25.172052] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:06:25.172427] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:06:25.172444] LOG: [APP] Upload success: +1 items (total: 30) -[2026-02-20T18:06:26.174277] LOG: [CONN] Frame received (80 bytes): 88 32 c7 15 08 7e 6b 22 6e 6b ef 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 ef b7 91 b3 63 -[2026-02-20T18:06:26.174329] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:26.174338] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:26.174357] LOG: [RX PARSE] RAW Packet (77 bytes): 15 08 7E 6B 22 6E 6B EF 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF B7 91 B3 63 -[2026-02-20T18:06:26.174362] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:26.174365] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:06:26.174374] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x7e, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes -[2026-02-20T18:06:26.174376] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:06:26.174381] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:26.174384] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:26.174399] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:26.174404] LOG: [RX FILTER] Raw packet (77 bytes): 15 08 7E 6B 22 6E 6B EF 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF B7 91 B3 63 -[2026-02-20T18:06:26.174409] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.5 -[2026-02-20T18:06:26.174414] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:06:26.174418] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:26.174420] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:26.174425] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:26.174429] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:06:26.174431] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:06:26.174457] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:06:26.174556] LOG: [RX FILTER] Decrypted message (58 chars): "tObLiN: @[MapperBot] 47.62796, -122.15860 [dt" -[2026-02-20T18:06:26.174563] LOG: [RX FILTER] Printable ratio: 77.6% (threshold: 60.0%) -[2026-02-20T18:06:26.174568] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:06:26.174576] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=8 -[2026-02-20T18:06:26.174580] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:06:26.174585] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:06:26.174591] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:06:26.174599] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:06:26.174605] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36133,-122.18668 -[2026-02-20T18:06:26.174610] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:06:26.174615] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36133,-122.18668 (batch tracking: 1 repeaters, rxCount: 20) -[2026-02-20T18:06:26.174622] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:06:26.174627] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36133,-122.18668 -[2026-02-20T18:06:26.753449] LOG: [GPS SERVICE] Position stream fired: lat=47.36222, lon=-122.18667, accuracy=3.8m -[2026-02-20T18:06:26.753505] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:06:26.753516] LOG: [RX BATCH] Distance check for repeater CC: 99.38m from first observation (threshold=25m) -[2026-02-20T18:06:26.753519] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:06:26.753522] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:06:26.753529] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:06:26.753534] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36133,-122.18668 -[2026-02-20T18:06:26.753537] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:06:26.753542] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36133,-122.18668 -[2026-02-20T18:06:26.753548] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:06:26.753554] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:06:26.753560] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=8 -[2026-02-20T18:06:26.753623] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:06:26.753629] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:06:27.602858] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:06:27.603016] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:27.734732] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:06:27.734869] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:06:27.734886] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:06:27.734906] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:06:27.793206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 0a 00 00 00 7e 23 00 00 -[2026-02-20T18:06:27.793337] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:27.793363] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:29.718125] LOG: [CONN] Frame received (65 bytes): 88 30 c6 15 09 93 23 56 1b 5a 53 7e 9b cc ad de 0b c7 7c b5 7d c2 6f 0d b2 2e b9 3c 53 af 5a e3 3b 33 4d ae 57 b4 a8 fb 18 5b f1 92 ed b3 9d 83 c5 35 a1 cb e1 f5 67 aa 4b f0 9a 91 43 29 80 c6 ef -[2026-02-20T18:06:29.718276] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:29.718315] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:29.718380] LOG: [RX PARSE] RAW Packet (62 bytes): 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF -[2026-02-20T18:06:29.718397] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:29.718408] LOG: [RX PARSE] Path length offset: 1, Path length: 9 -[2026-02-20T18:06:29.718453] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0x93, lastHop=0xcc, SNR=12.0, RSSI=-58, payload=51 bytes -[2026-02-20T18:06:29.718467] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 -[2026-02-20T18:06:29.718484] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:29.718494] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:29.718615] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:29.718621] LOG: [RX FILTER] Raw packet (62 bytes): 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF -[2026-02-20T18:06:29.718632] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 12.0 -[2026-02-20T18:06:29.718638] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:06:29.718660] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:29.718665] LOG: [RX FILTER] Channel hash: 0xad -[2026-02-20T18:06:29.718671] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad -[2026-02-20T18:06:29.718706] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:06:29.718714] LOG: [RX LOG] Dropped packet hex: 15 09 93 23 56 1B 5A 53 7E 9B CC AD DE 0B C7 7C B5 7D C2 6F 0D B2 2E B9 3C 53 AF 5A E3 3B 33 4D AE 57 B4 A8 FB 18 5B F1 92 ED B3 9D 83 C5 35 A1 CB E1 F5 67 AA 4B F0 9A 91 43 29 80 C6 EF -[2026-02-20T18:06:30.172851] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:06:31.756775] LOG: [GPS SERVICE] Position stream fired: lat=47.36312, lon=-122.18666, accuracy=3.8m -[2026-02-20T18:06:32.602956] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:32.776438] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c6 30 0a 00 00 00 7e 23 00 00 -[2026-02-20T18:06:32.776514] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:32.776524] LOG: [CONN] Noise floor updated: -117dBm -[2026-02-20T18:06:33.901708] LOG: [CONN] Frame received (83 bytes): 88 31 c2 15 0d 7e 75 20 20 20 75 c5 26 07 a5 e8 9b cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e 3a d4 39 7c bb af 68 96 77 c1 86 ef b7 91 -[2026-02-20T18:06:33.901854] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:33.901888] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:33.901977] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 -[2026-02-20T18:06:33.902] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:33.902012] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:06:33.902044] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=65 bytes -[2026-02-20T18:06:33.902063] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:06:33.902075] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:33.902090] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:33.902165] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:33.902178] LOG: [RX FILTER] Raw packet (80 bytes): 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 -[2026-02-20T18:06:33.902200] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 -[2026-02-20T18:06:33.902215] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:06:33.902231] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:33.902243] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:33.902254] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:33.902270] LOG: [RX FILTER] Encrypted message: 62 bytes -[2026-02-20T18:06:33.902281] LOG: [CRYPTO] Decrypting message (62 bytes) -[2026-02-20T18:06:33.902465] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:33.902605] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:33.902798] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:06:33.902897] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:06:33.902910] LOG: [RX LOG] Dropped packet hex: 15 0D 7E 75 20 20 20 75 C5 26 07 A5 E8 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E 3A D4 39 7C BB AF 68 96 77 C1 86 EF B7 91 -[2026-02-20T18:06:34.577460] LOG: [CONN] Frame received (83 bytes): 88 31 c3 15 0f 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 75 7e cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 ef -[2026-02-20T18:06:34.577625] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:34.577657] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:34.577735] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF -[2026-02-20T18:06:34.577757] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:34.577769] LOG: [RX PARSE] Path length offset: 1, Path length: 15 -[2026-02-20T18:06:34.577797] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=63 bytes -[2026-02-20T18:06:34.577811] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 -[2026-02-20T18:06:34.577826] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:34.577837] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:34.577939] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:34.577956] LOG: [RX FILTER] Raw packet (80 bytes): 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF -[2026-02-20T18:06:34.577976] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 12.25 -[2026-02-20T18:06:34.578005] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:06:34.578019] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:34.578030] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:34.578049] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:34.578063] LOG: [RX FILTER] Encrypted message: 60 bytes -[2026-02-20T18:06:34.578079] LOG: [CRYPTO] Decrypting message (60 bytes) -[2026-02-20T18:06:34.578255] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:34.578303] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:34.578595] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:06:34.578781] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:06:34.578794] LOG: [RX LOG] Dropped packet hex: 15 0F 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 75 7E CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 EF -[2026-02-20T18:06:36.765536] LOG: [GPS SERVICE] Position stream fired: lat=47.36400, lon=-122.18664, accuracy=4.3m -[2026-02-20T18:06:36.765589] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:06:36.765647] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:06:37.573648] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:06:37.573809] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:06:37.573816] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:06:37.574233] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:06:37.604869] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:37.788001] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0a 00 00 00 7f 23 00 00 -[2026-02-20T18:06:37.788131] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:37.788156] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:38.181451] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:06:38.181543] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:06:38.181566] LOG: [API] Response (200) in 0.61s: {"success":true,"expires_at":1771639897} -[2026-02-20T18:06:38.181585] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:06:38.181609] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:06:38.182336] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:06:38.182374] LOG: [APP] Upload success: +1 items (total: 31) -[2026-02-20T18:06:41.751307] LOG: [GPS SERVICE] Position stream fired: lat=47.36489, lon=-122.18663, accuracy=4.0m -[2026-02-20T18:06:42.604718] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:43.183346] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:06:43.530197] LOG: [CONN] Frame received (136 bytes): 88 31 c2 11 06 14 62 64 c7 9b cc bc 36 f1 2d 7e 9d 7d a3 ee 4f b1 81 bb 0f 9d 1b cc 5b 6f 29 38 5a 81 84 01 e8 b5 05 30 b2 9c c1 18 13 99 69 18 51 b3 ee 1f a9 bf 2b 7b 98 d4 50 ec 94 1e e8 0f da aa d8 1c 45 48 7e 05 f7 f8 76 64 7b 06 0c 10 e5 fd 21 e9 d5 55 73 5f 03 18 cd 86 d3 63 45 26 ca a2 51 f4 d6 77 42 b8 aa 11 13 e6 34 36 0e 92 40 8d d0 02 62 19 b1 f8 f0 9f 90 a2 46 49 20 4d 49 4e 49 20 54 45 53 54 -[2026-02-20T18:06:43.530290] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:43.530317] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:43.530403] LOG: [RX PARSE] RAW Packet (133 bytes): 11 06 14 62 64 C7 9B CC BC 36 F1 2D 7E 9D 7D A3 EE 4F B1 81 BB 0F 9D 1B CC 5B 6F 29 38 5A 81 84 01 E8 B5 05 30 B2 9C C1 18 13 99 69 18 51 B3 EE 1F A9 BF 2B 7B 98 D4 50 EC 94 1E E8 0F DA AA D8 1C 45 48 7E 05 F7 F8 76 64 7B 06 0C 10 E5 FD 21 E9 D5 55 73 5F 03 18 CD 86 D3 63 45 26 CA A2 51 F4 D6 77 42 B8 AA 11 13 E6 34 36 0E 92 40 8D D0 02 62 19 B1 F8 F0 9F 90 A2 46 49 20 4D 49 4E 49 20 54 45 53 54 -[2026-02-20T18:06:43.530424] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:06:43.530432] LOG: [RX PARSE] Path length offset: 1, Path length: 6 -[2026-02-20T18:06:43.530455] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=6, firstHop=0x14, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=125 bytes -[2026-02-20T18:06:43.530466] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=6 -[2026-02-20T18:06:43.530479] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:43.530487] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:43.530609] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:43.530624] LOG: [RX FILTER] Raw packet (133 bytes): 11 06 14 62 64 C7 9B CC BC 36 F1 2D 7E 9D 7D A3 EE 4F B1 81 BB 0F 9D 1B CC 5B 6F 29 38 5A 81 84 01 E8 B5 05 30 B2 9C C1 18 13 99 69 18 51 B3 EE 1F A9 BF 2B 7B 98 D4 50 EC 94 1E E8 0F DA AA D8 1C 45 48 7E 05 F7 F8 76 64 7B 06 0C 10 E5 FD 21 E9 D5 55 73 5F 03 18 CD 86 D3 63 45 26 CA A2 51 F4 D6 77 42 B8 AA 11 13 E6 34 36 0E 92 40 8D D0 02 62 19 B1 F8 F0 9F 90 A2 46 49 20 4D 49 4E 49 20 54 45 53 54 -[2026-02-20T18:06:43.530644] LOG: [RX FILTER] Header: 0x11 | PathLength: 6 | SNR: 12.25 -[2026-02-20T18:06:43.530656] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:06:43.530668] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:06:43.530677] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:06:43.530684] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:06:43.530780] LOG: [RX FILTER] ADVERT name extracted: "🐢FI MINI TEST" (14 chars) -[2026-02-20T18:06:43.530797] LOG: [RX FILTER] ADVERT name printable ratio: 85.7% -[2026-02-20T18:06:43.530805] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="🐢FI MINI TEST") -[2026-02-20T18:06:43.530827] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=6 -[2026-02-20T18:06:43.530838] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:06:43.530851] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:06:43.530863] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:06:43.530882] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:06:43.530897] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36489,-122.18663 -[2026-02-20T18:06:43.530914] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:06:43.530929] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36489,-122.18663 (batch tracking: 1 repeaters, rxCount: 21) -[2026-02-20T18:06:43.530949] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:06:43.530965] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36489,-122.18663 -[2026-02-20T18:06:43.540526] LOG: [CONN] Frame received (148 bytes): 8a bc 36 f1 2d 7e 9d 7d a3 ee 4f b1 81 bb 0f 9d 1b cc 5b 6f 29 38 5a 81 84 01 e8 b5 05 30 b2 9c c1 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 9f 90 a2 46 49 20 4d 49 4e 49 20 54 45 53 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 13 99 69 40 8d d0 02 62 19 b1 f8 31 13 99 69 -[2026-02-20T18:06:43.540541] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:06:43.540549] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:06:43.540951] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c1 32 0a 00 00 00 7f 23 00 00 -[2026-02-20T18:06:43.540957] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:43.540962] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:43.541340] LOG: [CONN] Frame received (93 bytes): 88 32 c1 15 1a 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 75 c5 a9 26 07 f4 18 50 7e ef db 9b cc 81 af 47 dd ff ca 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 c7 86 -[2026-02-20T18:06:43.541353] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:43.541362] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:43.541392] LOG: [RX PARSE] RAW Packet (90 bytes): 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 -[2026-02-20T18:06:43.541400] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:43.541406] LOG: [RX PARSE] Path length offset: 1, Path length: 26 -[2026-02-20T18:06:43.541415] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=26, firstHop=0x7e, lastHop=0xcc, SNR=12.5, RSSI=-63, payload=62 bytes -[2026-02-20T18:06:43.541422] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=26 -[2026-02-20T18:06:43.541425] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:43.541430] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:43.541457] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:43.541460] LOG: [RX FILTER] Raw packet (90 bytes): 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 -[2026-02-20T18:06:43.541469] LOG: [RX FILTER] Header: 0x15 | PathLength: 26 | SNR: 12.5 -[2026-02-20T18:06:43.541474] LOG: [RX FILTER] ✓ RSSI OK (-63 < -30) -[2026-02-20T18:06:43.541480] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:43.541484] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:06:43.541488] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:06:43.541499] LOG: [RX FILTER] Encrypted message: 59 bytes -[2026-02-20T18:06:43.541503] LOG: [CRYPTO] Decrypting message (59 bytes) -[2026-02-20T18:06:43.541573] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:43.541590] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:43.541701] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:06:43.541741] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:06:43.541745] LOG: [RX LOG] Dropped packet hex: 15 1A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 75 C5 A9 26 07 F4 18 50 7E EF DB 9B CC 81 AF 47 DD FF CA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 C7 86 -[2026-02-20T18:06:46.764870] LOG: [GPS SERVICE] Position stream fired: lat=47.36568, lon=-122.18657, accuracy=4.0m -[2026-02-20T18:06:46.764915] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:06:46.764925] LOG: [RX BATCH] Distance check for repeater CC: 88.07m from first observation (threshold=25m) -[2026-02-20T18:06:46.764929] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:06:46.764932] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:06:46.764938] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:06:46.764945] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36489,-122.18663 -[2026-02-20T18:06:46.764948] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:06:46.764951] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36489,-122.18663 -[2026-02-20T18:06:46.764958] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:06:46.764962] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:06:46.764967] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=6 -[2026-02-20T18:06:46.765017] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:06:46.765021] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:06:47.603651] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:47.653094] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c1 32 0a 00 00 00 80 23 00 00 -[2026-02-20T18:06:47.653258] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:47.653278] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:49.928194] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:06:49.928368] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:06:49.928388] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:06:49.928443] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:06:49.928489] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36568, -122.18657 [0.3w]" -[2026-02-20T18:06:49.928507] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:06:49.928517] LOG: [TX LOG] Payload: "@[MapperBot] 47.36568, -122.18657 [0.3w]" -[2026-02-20T18:06:49.928532] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:06:49.928551] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:06:49.928564] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:06:49.928574] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:06:49.928604] LOG: [CONN] Sending ping: @[MapperBot] 47.36568, -122.18657 [0.3w] -[2026-02-20T18:06:50.112865] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:06:50.112986] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:06:50.112995] LOG: [CONN] Received OK response -[2026-02-20T18:06:51.260400] LOG: [CONN] Frame received (73 bytes): 88 2f c2 15 01 cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 48 82 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:06:51.260457] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:51.260498] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:51.260567] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:06:51.260588] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:51.260601] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:06:51.260629] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=67 bytes -[2026-02-20T18:06:51.260648] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:06:51.260657] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:06:51.260673] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-62 -[2026-02-20T18:06:51.260683] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:06:51.260693] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:06:51.260803] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:51.260816] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:51.260832] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:06:51.757838] LOG: [GPS SERVICE] Position stream fired: lat=47.36632, lon=-122.18659, accuracy=3.9m -[2026-02-20T18:06:52.574328] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:06:52.574688] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:06:52.574712] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:06:52.575759] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:06:52.602963] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:52.662316] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0b 00 00 00 80 23 00 00 -[2026-02-20T18:06:52.662389] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:52.662402] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:06:53.058226] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:06:53.058311] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:06:53.058327] LOG: [API] Response (200) in 0.48s: {"success":true,"expires_at":1771639912} -[2026-02-20T18:06:53.058351] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:06:53.058370] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:06:53.058801] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:06:53.058820] LOG: [APP] Upload success: +1 items (total: 32) -[2026-02-20T18:06:53.116189] LOG: [PING] Ping sent successfully -[2026-02-20T18:06:53.669607] LOG: [CONN] Frame received (44 bytes): 88 32 c5 15 04 1f ab 7e cc ca 88 50 62 ce b1 0a a1 32 31 e3 7b 98 ca 6a 7b 2e 4e 54 4b 2b 1b 4a 2d 94 83 18 d9 5b 07 a9 92 05 80 49 -[2026-02-20T18:06:53.669702] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:53.669725] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:53.669755] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 1F AB 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 80 49 -[2026-02-20T18:06:53.669763] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:53.669772] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:06:53.669786] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=35 bytes -[2026-02-20T18:06:53.669797] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:06:53.669803] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:06:53.669810] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-59 -[2026-02-20T18:06:53.669825] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:06:53.669833] LOG: [TX LOG] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:06:53.669843] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xca, expected=0x81 -[2026-02-20T18:06:53.669850] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:06:53.669857] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:53.669866] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:53.669894] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:53.669900] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 1F AB 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 80 49 -[2026-02-20T18:06:53.669912] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.5 -[2026-02-20T18:06:53.669920] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:06:53.669928] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:53.669937] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:06:53.669944] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:06:53.669953] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:06:53.669961] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:06:53.670003] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:06:53.670101] LOG: [RX FILTER] Decrypted message (14 chars): "DieterPibbs: T" -[2026-02-20T18:06:53.670115] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:06:53.670121] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:06:53.670140] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=4 -[2026-02-20T18:06:53.670149] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:06:53.670160] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:06:53.670171] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:06:53.670188] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:06:53.670199] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36632,-122.18659 -[2026-02-20T18:06:53.670214] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:06:53.670228] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36632,-122.18659 (batch tracking: 1 repeaters, rxCount: 22) -[2026-02-20T18:06:53.670247] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:06:53.670259] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36632,-122.18659 -[2026-02-20T18:06:54.930319] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:06:56.752927] LOG: [GPS SERVICE] Position stream fired: lat=47.36661, lon=-122.18646, accuracy=3.8m -[2026-02-20T18:06:56.752983] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:06:56.752996] LOG: [RX BATCH] Distance check for repeater CC: 33.60m from first observation (threshold=25m) -[2026-02-20T18:06:56.753] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:06:56.753003] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:06:56.753011] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:06:56.753016] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36632,-122.18659 -[2026-02-20T18:06:56.753021] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:06:56.753027] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36632,-122.18659 -[2026-02-20T18:06:56.753033] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:06:56.753041] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:06:56.753045] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=4 -[2026-02-20T18:06:56.753111] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:06:56.753117] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:06:57.287931] LOG: [CONN] Frame received (63 bytes): 88 31 c9 15 07 c6 38 be 18 50 7e cc 23 bc 62 a5 44 88 7b 01 91 c5 31 2c 43 54 97 3c 90 77 e6 26 70 1d 58 6e 8e 8c 80 77 fa a8 cc f0 2d 19 70 cf 8d 08 b6 c3 db 90 a2 f6 37 60 e9 77 c7 cd 89 -[2026-02-20T18:06:57.288085] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:57.288122] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:57.288182] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 -[2026-02-20T18:06:57.288201] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:57.288213] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:06:57.288250] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xc6, lastHop=0xcc, SNR=12.25, RSSI=-55, payload=51 bytes -[2026-02-20T18:06:57.288265] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:06:57.288276] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:57.288290] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:57.288346] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:57.288362] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 -[2026-02-20T18:06:57.288380] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 -[2026-02-20T18:06:57.288400] LOG: [RX FILTER] ✓ RSSI OK (-55 < -30) -[2026-02-20T18:06:57.288413] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:57.288423] LOG: [RX FILTER] Channel hash: 0x23 -[2026-02-20T18:06:57.288439] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x23 -[2026-02-20T18:06:57.288510] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:06:57.288522] LOG: [RX LOG] Dropped packet hex: 15 07 C6 38 BE 18 50 7E CC 23 BC 62 A5 44 88 7B 01 91 C5 31 2C 43 54 97 3C 90 77 E6 26 70 1D 58 6E 8E 8C 80 77 FA A8 CC F0 2D 19 70 CF 8D 08 B6 C3 DB 90 A2 F6 37 60 E9 77 C7 CD 89 -[2026-02-20T18:06:57.603112] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:06:57.603382] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:06:57.795377] LOG: [CONN] Frame received (11 bytes): 0c cc 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:06:57.795520] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:06:57.795544] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:06:57.795560] LOG: [CONN] Battery updated: 4044mV (87%) -[2026-02-20T18:06:57.854806] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c9 31 0b 00 00 00 81 23 00 00 -[2026-02-20T18:06:57.854928] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:06:57.854955] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:06:57.976614] LOG: [CONN] Frame received (49 bytes): 88 32 cc 15 0b 1f ab 7e 75 20 20 20 53 7a 7e cc ca 88 50 62 ce b1 0a a1 32 31 e3 7b 98 ca 6a 7b 2e 4e 54 4b 2b 1b 4a 2d 94 83 18 d9 5b 07 a9 92 05 -[2026-02-20T18:06:57.976769] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:06:57.976799] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:06:57.976856] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 -[2026-02-20T18:06:57.976871] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:06:57.976887] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:06:57.976910] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-52, payload=33 bytes -[2026-02-20T18:06:57.976928] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:06:57.976940] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:06:57.976950] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:06:57.976994] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:06:57.977009] LOG: [RX FILTER] Raw packet (46 bytes): 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 -[2026-02-20T18:06:57.977026] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 -[2026-02-20T18:06:57.977047] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:06:57.977059] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:06:57.977069] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:06:57.977085] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:06:57.977097] LOG: [RX FILTER] Encrypted message: 30 bytes -[2026-02-20T18:06:57.977112] LOG: [CRYPTO] Decrypting message (30 bytes) -[2026-02-20T18:06:57.977265] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:57.977324] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:06:57.977558] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:06:57.977649] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:06:57.977661] LOG: [RX LOG] Dropped packet hex: 15 0B 1F AB 7E 75 20 20 20 53 7A 7E CC CA 88 50 62 CE B1 0A A1 32 31 E3 7B 98 CA 6A 7B 2E 4E 54 4B 2B 1B 4A 2D 94 83 18 D9 5B 07 A9 92 05 -[2026-02-20T18:06:58.059716] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:06:58.116565] LOG: [PING] RX listening window ended -[2026-02-20T18:06:58.116605] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:06:58.116615] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:06:58.116640] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:06:58.116643] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:06:58.116646] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:06:58.116654] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:06:58.116657] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:06:58.116933] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:07:01.752211] LOG: [GPS SERVICE] Position stream fired: lat=47.36658, lon=-122.18597, accuracy=3.8m -[2026-02-20T18:07:02.603038] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:02.683296] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0b 00 00 00 81 23 00 00 -[2026-02-20T18:07:02.683431] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:02.683457] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:03.119021] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:07:03.119261] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:07:03.119278] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:07:03.119297] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:07:03.120330] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:07:03.381586] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:07:03.381614] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:07:03.381618] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771639923} -[2026-02-20T18:07:03.381624] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:07:03.381629] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:07:03.382889] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:07:03.382903] LOG: [APP] Upload success: +2 items (total: 34) -[2026-02-20T18:07:06.749083] LOG: [GPS SERVICE] Position stream fired: lat=47.36625, lon=-122.18500, accuracy=3.8m -[2026-02-20T18:07:07.573882] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:07:07.574066] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:07:07.604745] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:07.693409] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0b 00 00 00 81 23 00 00 -[2026-02-20T18:07:07.693546] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:07.693566] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:08.386586] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:07:08.571794] LOG: [CONN] Frame received (144 bytes): 88 31 c6 15 08 51 01 e0 7a ab 7e 9b cc ca bc 14 56 e3 ea 8c 46 76 17 84 73 e9 3f 9a 38 a3 e2 8b c0 44 4b 24 e7 42 90 5d 57 e1 65 9c 39 47 19 c8 47 24 18 0a e8 7c d5 f7 b2 7e bf b8 68 b9 85 4e 21 50 6d 56 30 1b 69 c9 cd 1a dc d0 93 de 05 6d 57 9f 15 1c f9 32 ed ba 95 a3 9d 72 b4 8e b4 7d 5d 3b 98 1d 7c fc 72 a8 20 cc d9 cd 0a 91 2d a7 8b 42 31 3c 76 9e 11 91 01 b6 f7 8f a9 5d d8 69 e1 84 2c d5 39 38 84 d1 ea 99 09 be 39 f8 de 14 -[2026-02-20T18:07:08.571946] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:08.571983] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:08.572101] LOG: [RX PARSE] RAW Packet (141 bytes): 15 08 51 01 E0 7A AB 7E 9B CC CA BC 14 56 E3 EA 8C 46 76 17 84 73 E9 3F 9A 38 A3 E2 8B C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 47 24 18 0A E8 7C D5 F7 B2 7E BF B8 68 B9 85 4E 21 50 6D 56 30 1B 69 C9 CD 1A DC D0 93 DE 05 6D 57 9F 15 1C F9 32 ED BA 95 A3 9D 72 B4 8E B4 7D 5D 3B 98 1D 7C FC 72 A8 20 CC D9 CD 0A 91 2D A7 8B 42 31 3C 76 9E 11 91 01 B6 F7 8F A9 5D D8 69 E1 84 2C D5 39 38 84 D1 EA 99 09 BE 39 F8 DE 14 -[2026-02-20T18:07:08.572128] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:08.572143] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:07:08.572174] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x51, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=131 bytes -[2026-02-20T18:07:08.572194] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:07:08.572205] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:08.572215] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:08.572388] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:08.572402] LOG: [RX FILTER] Raw packet (141 bytes): 15 08 51 01 E0 7A AB 7E 9B CC CA BC 14 56 E3 EA 8C 46 76 17 84 73 E9 3F 9A 38 A3 E2 8B C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 47 24 18 0A E8 7C D5 F7 B2 7E BF B8 68 B9 85 4E 21 50 6D 56 30 1B 69 C9 CD 1A DC D0 93 DE 05 6D 57 9F 15 1C F9 32 ED BA 95 A3 9D 72 B4 8E B4 7D 5D 3B 98 1D 7C FC 72 A8 20 CC D9 CD 0A 91 2D A7 8B 42 31 3C 76 9E 11 91 01 B6 F7 8F A9 5D D8 69 E1 84 2C D5 39 38 84 D1 EA 99 09 BE 39 F8 DE 14 -[2026-02-20T18:07:08.572430] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 -[2026-02-20T18:07:08.572449] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:07:08.572461] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:08.572472] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:07:08.572488] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:07:08.572500] LOG: [RX FILTER] Encrypted message: 128 bytes -[2026-02-20T18:07:08.572547] LOG: [CRYPTO] Decrypting message (128 bytes) -[2026-02-20T18:07:08.572672] LOG: [CRYPTO] Decrypted successfully (128 bytes) -[2026-02-20T18:07:08.572859] LOG: [RX FILTER] Decrypted message (116 chars): "HowlBot: ack @[DieterPibbs] | 1f,17,53,e0 | Path Dist: 48.8k..." -[2026-02-20T18:07:08.572889] LOG: [RX FILTER] Printable ratio: 98.3% (threshold: 60.0%) -[2026-02-20T18:07:08.572899] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:07:08.572930] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=8 -[2026-02-20T18:07:08.572941] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:07:08.572963] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:07:08.572980] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:07:08.573004] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:07:08.573029] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36625,-122.18500 -[2026-02-20T18:07:08.573053] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:07:08.573077] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36625,-122.18500 (batch tracking: 1 repeaters, rxCount: 23) -[2026-02-20T18:07:08.573105] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:07:08.573125] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36625,-122.18500 -[2026-02-20T18:07:11.777288] LOG: [GPS SERVICE] Position stream fired: lat=47.36590, lon=-122.18396, accuracy=3.8m -[2026-02-20T18:07:11.777334] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:07:11.777351] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:07:11.777358] LOG: [RX BATCH] Distance check for repeater CC: 87.78m from first observation (threshold=25m) -[2026-02-20T18:07:11.777375] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:07:11.777378] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:07:11.777382] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:07:11.777388] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36625,-122.18500 -[2026-02-20T18:07:11.777392] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:07:11.777394] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36625,-122.18500 -[2026-02-20T18:07:11.777402] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:07:11.777407] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:07:11.777412] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=8 -[2026-02-20T18:07:11.777459] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:07:11.777477] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:07:11.777480] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:07:12.603001] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:12.675769] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c6 31 0b 00 00 00 81 23 00 00 -[2026-02-20T18:07:12.675898] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:12.675917] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:07:13.260303] LOG: [CONN] Frame received (91 bytes): 88 2f c8 15 17 cc 9b e8 86 2b 75 20 20 20 20 20 75 ee 66 6a 82 ea 1f a3 74 41 7e cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 48 82 19 55 94 25 e0 39 e7 92 a9 03 64 ee -[2026-02-20T18:07:13.260429] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:13.260457] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:13.260537] LOG: [RX PARSE] RAW Packet (88 bytes): 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:07:13.260559] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:13.260570] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T18:07:13.260611] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=63 bytes -[2026-02-20T18:07:13.260624] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 -[2026-02-20T18:07:13.260639] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:13.260650] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:13.260662] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B -[2026-02-20T18:07:13.260739] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:13.260751] LOG: [RX FILTER] Raw packet (88 bytes): 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:07:13.260773] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.75 -[2026-02-20T18:07:13.260783] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:07:13.260793] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:13.260808] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:07:13.260820] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:07:13.260832] LOG: [RX FILTER] Encrypted message: 60 bytes -[2026-02-20T18:07:13.260846] LOG: [CRYPTO] Decrypting message (60 bytes) -[2026-02-20T18:07:13.261010] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:13.261062] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:13.261278] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:07:13.261411] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:07:13.261423] LOG: [RX LOG] Dropped packet hex: 15 17 CC 9B E8 86 2B 75 20 20 20 20 20 75 EE 66 6A 82 EA 1F A3 74 41 7E CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 48 82 19 55 94 25 E0 39 E7 92 A9 03 64 EE -[2026-02-20T18:07:16.751993] LOG: [GPS SERVICE] Position stream fired: lat=47.36553, lon=-122.18293, accuracy=3.8m -[2026-02-20T18:07:17.602669] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:17.652414] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 2f 0b 00 00 00 82 23 00 00 -[2026-02-20T18:07:17.652531] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:17.652555] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:21.508306] LOG: [CONN] Frame received (80 bytes): 88 31 c6 15 18 cc 9b e8 86 ab 2a 94 de a4 c9 bb b2 43 bf 23 56 1b 28 aa cd 6c c7 7e cc 81 d2 e7 1b ba a3 5a 7d f4 71 55 4b 1a 67 a7 f5 32 c3 c7 3d d9 b2 9e a4 9c 21 f6 27 6e a8 89 76 75 d7 91 04 00 22 de 0b 01 10 56 25 e6 ce 5b c1 09 9e 28 -[2026-02-20T18:07:21.508327] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:21.508342] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:21.508360] LOG: [RX PARSE] RAW Packet (77 bytes): 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 -[2026-02-20T18:07:21.508365] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:21.508368] LOG: [RX PARSE] Path length offset: 1, Path length: 24 -[2026-02-20T18:07:21.508377] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=24, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=51 bytes -[2026-02-20T18:07:21.508380] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=24 -[2026-02-20T18:07:21.508384] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:21.508386] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:21.508389] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B -[2026-02-20T18:07:21.508406] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:21.508409] LOG: [RX FILTER] Raw packet (77 bytes): 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 -[2026-02-20T18:07:21.508414] LOG: [RX FILTER] Header: 0x15 | PathLength: 24 | SNR: 12.25 -[2026-02-20T18:07:21.508418] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:07:21.508421] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:21.508423] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:07:21.508428] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:07:21.508431] LOG: [RX FILTER] Encrypted message: 48 bytes -[2026-02-20T18:07:21.508433] LOG: [CRYPTO] Decrypting message (48 bytes) -[2026-02-20T18:07:21.508458] LOG: [CRYPTO] Decrypted successfully (48 bytes) -[2026-02-20T18:07:21.508524] LOG: [RX FILTER] Decrypted message (39 chars): "!H|76Qy7Wp[H!d" -[2026-02-20T18:07:21.508531] LOG: [RX FILTER] Printable ratio: 35.9% (threshold: 60.0%) -[2026-02-20T18:07:21.508535] LOG: [RX FILTER] ❌ DROPPED: plaintext not printable -[2026-02-20T18:07:21.508587] LOG: [RX LOG] ❌ Packet dropped: plaintext not printable -[2026-02-20T18:07:21.508592] LOG: [RX LOG] Dropped packet hex: 15 18 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E CC 81 D2 E7 1B BA A3 5A 7D F4 71 55 4B 1A 67 A7 F5 32 C3 C7 3D D9 B2 9E A4 9C 21 F6 27 6E A8 89 76 75 D7 91 04 00 22 DE 0B 01 10 56 25 E6 CE 5B C1 09 9E 28 -[2026-02-20T18:07:21.762783] LOG: [GPS SERVICE] Position stream fired: lat=47.36518, lon=-122.18189, accuracy=3.8m -[2026-02-20T18:07:22.574218] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:07:22.574462] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:07:22.574475] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:07:22.576145] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:07:22.602620] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:22.782612] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 0b 00 00 00 82 23 00 00 -[2026-02-20T18:07:22.782769] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:22.782793] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:23.070129] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:07:23.070232] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:07:23.070251] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771639942} -[2026-02-20T18:07:23.070269] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:07:23.070292] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:07:23.070738] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:07:23.070746] LOG: [APP] Upload success: +1 items (total: 35) -[2026-02-20T18:07:25.471584] LOG: [CONN] Frame received (63 bytes): 88 31 c6 15 07 f7 e3 7e 6f e8 9b cc 5b 14 5a d1 b0 ab 86 11 a9 7a 06 24 58 53 d3 7a 92 46 64 7e be 30 9c 11 53 80 4b 00 e7 aa d3 cb 77 64 35 f3 c4 44 03 67 69 a6 2a 98 f1 b0 df 7e 09 cf e3 -[2026-02-20T18:07:25.471781] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:25.471812] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:25.471879] LOG: [RX PARSE] RAW Packet (60 bytes): 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 -[2026-02-20T18:07:25.471896] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:25.471911] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:07:25.471935] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xf7, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=51 bytes -[2026-02-20T18:07:25.471954] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:07:25.471966] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:25.471975] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:25.472034] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:25.472047] LOG: [RX FILTER] Raw packet (60 bytes): 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 -[2026-02-20T18:07:25.472070] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 -[2026-02-20T18:07:25.472085] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:07:25.472101] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:25.472112] LOG: [RX FILTER] Channel hash: 0x5b -[2026-02-20T18:07:25.472123] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x5b -[2026-02-20T18:07:25.472260] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:07:25.472274] LOG: [RX LOG] Dropped packet hex: 15 07 F7 E3 7E 6F E8 9B CC 5B 14 5A D1 B0 AB 86 11 A9 7A 06 24 58 53 D3 7A 92 46 64 7E BE 30 9C 11 53 80 4B 00 E7 AA D3 CB 77 64 35 F3 C4 44 03 67 69 A6 2A 98 F1 B0 DF 7E 09 CF E3 -[2026-02-20T18:07:26.755263] LOG: [GPS SERVICE] Position stream fired: lat=47.36480, lon=-122.18086, accuracy=3.8m -[2026-02-20T18:07:27.603269] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:07:27.603404] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:27.649166] LOG: [CONN] Frame received (47 bytes): 88 2f c6 15 07 4e dc 1f 7e 52 9b cc ca f7 c9 93 32 3d 47 31 51 b2 d8 02 c7 93 70 84 4b 23 73 86 73 a8 4f 6d 6b c8 2a bb f8 bd a3 94 a5 5b 4b -[2026-02-20T18:07:27.649241] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:27.649258] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:27.649284] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 4E DC 1F 7E 52 9B CC CA F7 C9 93 32 3D 47 31 51 B2 D8 02 C7 93 70 84 4B 23 73 86 73 A8 4F 6D 6B C8 2A BB F8 BD A3 94 A5 5B 4B -[2026-02-20T18:07:27.649294] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:27.649300] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:07:27.649319] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x4e, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=35 bytes -[2026-02-20T18:07:27.649326] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:07:27.649331] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:27.649340] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:27.649365] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:27.649371] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 4E DC 1F 7E 52 9B CC CA F7 C9 93 32 3D 47 31 51 B2 D8 02 C7 93 70 84 4B 23 73 86 73 A8 4F 6D 6B C8 2A BB F8 BD A3 94 A5 5B 4B -[2026-02-20T18:07:27.649383] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.75 -[2026-02-20T18:07:27.649391] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:07:27.649399] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:27.649406] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:07:27.649412] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:07:27.649421] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:07:27.649427] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:07:27.649465] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:07:27.649562] LOG: [RX FILTER] Decrypted message (15 chars): "DieterPibbs1: T" -[2026-02-20T18:07:27.649574] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:07:27.649583] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:07:27.649599] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=7 -[2026-02-20T18:07:27.649609] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:07:27.649619] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 -[2026-02-20T18:07:27.649631] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:07:27.649644] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:07:27.649659] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.36480,-122.18086 -[2026-02-20T18:07:27.649669] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:07:27.649680] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36480,-122.18086 (batch tracking: 1 repeaters, rxCount: 24) -[2026-02-20T18:07:27.649693] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:07:27.649705] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.36480,-122.18086 -[2026-02-20T18:07:27.674261] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:07:27.674303] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:07:27.674311] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:07:27.674317] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:07:27.733205] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c6 2f 0b 00 00 00 82 23 00 00 -[2026-02-20T18:07:27.733343] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:27.733363] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:07:28.072397] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:07:28.118966] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:07:28.119004] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:07:28.119010] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:07:28.119025] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:07:28.119040] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36480, -122.18086 [0.3w]" -[2026-02-20T18:07:28.119044] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:07:28.119046] LOG: [TX LOG] Payload: "@[MapperBot] 47.36480, -122.18086 [0.3w]" -[2026-02-20T18:07:28.119051] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:07:28.119054] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:07:28.119058] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:07:28.119062] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:07:28.119066] LOG: [CONN] Sending ping: @[MapperBot] 47.36480, -122.18086 [0.3w] -[2026-02-20T18:07:28.245140] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:07:28.245237] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:07:28.245247] LOG: [CONN] Received OK response -[2026-02-20T18:07:29.519374] LOG: [CONN] Frame received (73 bytes): 88 32 c6 15 01 cc 81 58 24 86 df eb 48 98 a0 5b 4f cd 25 22 32 90 66 70 76 b3 2f 2c a3 52 ab 74 b0 67 13 86 72 e7 6a 4a 03 3a 3c 17 6a f8 82 15 16 d9 27 e2 42 ed 7b c7 a2 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:07:29.519472] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:29.519527] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:29.519582] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 58 24 86 DF EB 48 98 A0 5B 4F CD 25 22 32 90 66 70 76 B3 2F 2C A3 52 AB 74 B0 67 13 86 72 E7 6A 4A 03 3A 3C 17 6A F8 82 15 16 D9 27 E2 42 ED 7B C7 A2 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:07:29.519597] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:29.519605] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:07:29.519629] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-58, payload=67 bytes -[2026-02-20T18:07:29.519640] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:07:29.519647] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:07:29.519659] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-58 -[2026-02-20T18:07:29.519667] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:07:29.519674] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:07:29.519687] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:29.519694] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:29.519704] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:07:31.245886] LOG: [PING] Ping sent successfully -[2026-02-20T18:07:31.746811] LOG: [GPS SERVICE] Position stream fired: lat=47.36447, lon=-122.17986, accuracy=3.8m -[2026-02-20T18:07:31.746856] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:07:31.746867] LOG: [RX BATCH] Distance check for repeater CC: 83.75m from first observation (threshold=25m) -[2026-02-20T18:07:31.746870] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:07:31.746873] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:07:31.746879] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:07:31.746885] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.36480,-122.18086 -[2026-02-20T18:07:31.746888] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:07:31.746894] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.36480,-122.18086 -[2026-02-20T18:07:31.746900] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 -[2026-02-20T18:07:31.746906] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:07:31.746911] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=7 -[2026-02-20T18:07:31.746967] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:07:31.746972] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:07:32.606854] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:32.772453] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 32 0b 00 00 00 83 23 00 00 -[2026-02-20T18:07:32.772500] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:32.772506] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:32.957195] LOG: [CONN] Frame received (140 bytes): 88 31 c7 15 04 7a 7e 9b cc ca 82 31 72 2d 6a 6e 0e fd bf f9 30 1c d5 0e 7b f5 2d 46 c0 44 4b 24 e7 42 90 5d 57 e1 65 9c 39 47 19 c8 71 fb 08 84 8e 64 bb 95 0d 86 6c 82 54 d2 66 4c d8 1c 79 c2 92 19 a0 24 78 75 13 4a 5e 33 b0 a5 48 53 d0 1c 76 0f 06 78 25 74 be 8a 89 6d ca d3 b8 14 4f 8c 4e 23 7b a2 f4 42 77 99 d8 d2 e6 cb ad 90 ea c0 8a 4f 41 69 22 3c bc 63 8a a6 25 cb 7e da ab ab 3b cc 3f be ec d3 5c a5 48 9f 37 af -[2026-02-20T18:07:32.957363] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:32.957394] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:32.957526] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 7A 7E 9B CC CA 82 31 72 2D 6A 6E 0E FD BF F9 30 1C D5 0E 7B F5 2D 46 C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 71 FB 08 84 8E 64 BB 95 0D 86 6C 82 54 D2 66 4C D8 1C 79 C2 92 19 A0 24 78 75 13 4A 5E 33 B0 A5 48 53 D0 1C 76 0F 06 78 25 74 BE 8A 89 6D CA D3 B8 14 4F 8C 4E 23 7B A2 F4 42 77 99 D8 D2 E6 CB AD 90 EA C0 8A 4F 41 69 22 3C BC 63 8A A6 25 CB 7E DA AB AB 3B CC 3F BE EC D3 5C A5 48 9F 37 AF -[2026-02-20T18:07:32.957579] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:32.957591] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:07:32.957618] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x7a, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=131 bytes -[2026-02-20T18:07:32.957633] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:07:32.957643] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:07:32.957661] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 -[2026-02-20T18:07:32.957671] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:07:32.957691] LOG: [TX LOG] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:07:32.957704] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xca, expected=0x81 -[2026-02-20T18:07:32.957715] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:07:32.957733] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:32.957743] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:32.957858] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:32.957874] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 7A 7E 9B CC CA 82 31 72 2D 6A 6E 0E FD BF F9 30 1C D5 0E 7B F5 2D 46 C0 44 4B 24 E7 42 90 5D 57 E1 65 9C 39 47 19 C8 71 FB 08 84 8E 64 BB 95 0D 86 6C 82 54 D2 66 4C D8 1C 79 C2 92 19 A0 24 78 75 13 4A 5E 33 B0 A5 48 53 D0 1C 76 0F 06 78 25 74 BE 8A 89 6D CA D3 B8 14 4F 8C 4E 23 7B A2 F4 42 77 99 D8 D2 E6 CB AD 90 EA C0 8A 4F 41 69 22 3C BC 63 8A A6 25 CB 7E DA AB AB 3B CC 3F BE EC D3 5C A5 48 9F 37 AF -[2026-02-20T18:07:32.957902] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.25 -[2026-02-20T18:07:32.957915] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:07:32.957931] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:32.957943] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:07:32.957955] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:07:32.957971] LOG: [RX FILTER] Encrypted message: 128 bytes -[2026-02-20T18:07:32.957984] LOG: [CRYPTO] Decrypting message (128 bytes) -[2026-02-20T18:07:32.958123] LOG: [CRYPTO] Decrypted successfully (128 bytes) -[2026-02-20T18:07:32.958313] LOG: [RX FILTER] Decrypted message (121 chars): "HowlBot: ack @[DieterPibbs1] | 4e,dc,1f,7e,7a | Path Dist: 2..." -[2026-02-20T18:07:32.958340] LOG: [RX FILTER] Printable ratio: 98.3% (threshold: 60.0%) -[2026-02-20T18:07:32.958349] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:07:32.958381] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=4 -[2026-02-20T18:07:32.958397] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:07:32.958420] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:07:32.958437] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:07:32.958463] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:07:32.958484] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36447,-122.17986 -[2026-02-20T18:07:32.958508] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:07:32.958677] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36447,-122.17986 (batch tracking: 1 repeaters, rxCount: 25) -[2026-02-20T18:07:32.958691] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:07:32.958701] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36447,-122.17986 -[2026-02-20T18:07:33.122506] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:07:36.246885] LOG: [PING] RX listening window ended -[2026-02-20T18:07:36.247033] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:07:36.247074] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:07:36.247144] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:07:36.247155] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:07:36.247168] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:07:36.247188] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:07:36.247200] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:07:36.247994] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:07:36.764875] LOG: [GPS SERVICE] Position stream fired: lat=47.36413, lon=-122.17896, accuracy=3.8m -[2026-02-20T18:07:36.764914] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:07:36.764922] LOG: [RX BATCH] Distance check for repeater CC: 77.73m from first observation (threshold=25m) -[2026-02-20T18:07:36.764928] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:07:36.764930] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:07:36.764935] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:07:36.764940] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36447,-122.17986 -[2026-02-20T18:07:36.764943] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:07:36.764948] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36447,-122.17986 -[2026-02-20T18:07:36.764953] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:07:36.764958] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:07:36.764963] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=4 -[2026-02-20T18:07:36.765013] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:07:36.765018] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:07:37.574319] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:07:37.574691] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:07:37.574714] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:07:37.574727] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:07:37.576467] LOG: [API QUEUE] Flushed 2 RX items from 1 repeaters to queue -[2026-02-20T18:07:37.602637] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:37.663635] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0b 00 00 00 83 23 00 00 -[2026-02-20T18:07:37.663766] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:37.663785] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:38.069071] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:07:38.069176] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:07:38.069195] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771639957} -[2026-02-20T18:07:38.069221] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:07:38.069239] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:07:38.069961] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:07:38.069979] LOG: [APP] Upload success: +2 items (total: 37) -[2026-02-20T18:07:41.249100] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:07:41.250058] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:07:41.250074] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:07:41.586779] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:07:41.586823] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:07:41.586838] LOG: [API] Response (200) in 0.34s: {"success":true,"expires_at":1771639961} -[2026-02-20T18:07:41.586859] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:07:41.586876] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:07:41.587458] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:07:41.587476] LOG: [APP] Upload success: +1 items (total: 38) -[2026-02-20T18:07:41.748442] LOG: [GPS SERVICE] Position stream fired: lat=47.36384, lon=-122.17816, accuracy=3.9m -[2026-02-20T18:07:42.603060] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:42.673862] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 31 0b 00 00 00 83 23 00 00 -[2026-02-20T18:07:42.673990] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:42.674010] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:07:46.587727] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:07:46.764171] LOG: [GPS SERVICE] Position stream fired: lat=47.36359, lon=-122.17744, accuracy=3.8m -[2026-02-20T18:07:46.764258] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:07:46.764283] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:07:47.602748] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:47.687833] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0b 00 00 00 83 23 00 00 -[2026-02-20T18:07:47.687928] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:47.687948] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:07:48.268168] LOG: [CONN] Frame received (69 bytes): 88 2e c7 15 37 cc 9b e8 86 ab 2a 94 de a4 c9 bb b2 43 bf 23 56 1b 28 aa cd 6c c7 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 20 ab 7e cc 81 d2 e7 1b ba a3 5a 7d f4 -[2026-02-20T18:07:48.268223] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:48.268237] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:48.268254] LOG: [RX PARSE] RAW Packet (66 bytes): 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 -[2026-02-20T18:07:48.268258] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:48.268262] LOG: [RX PARSE] Path length offset: 1, Path length: 55 -[2026-02-20T18:07:48.268273] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=55, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-57, payload=9 bytes -[2026-02-20T18:07:48.268278] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=55 -[2026-02-20T18:07:48.268282] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:48.268284] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:48.268289] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B -[2026-02-20T18:07:48.268303] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:48.268309] LOG: [RX FILTER] Raw packet (66 bytes): 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 -[2026-02-20T18:07:48.268313] LOG: [RX FILTER] Header: 0x15 | PathLength: 55 | SNR: 11.5 -[2026-02-20T18:07:48.268318] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:07:48.268322] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:48.268324] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:07:48.268331] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:07:48.268334] LOG: [RX FILTER] Encrypted message: 6 bytes -[2026-02-20T18:07:48.268336] LOG: [CRYPTO] Decrypting message (6 bytes) -[2026-02-20T18:07:48.268393] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:48.268407] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:48.268485] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:07:48.268514] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:07:48.268517] LOG: [RX LOG] Dropped packet hex: 15 37 CC 9B E8 86 AB 2A 94 DE A4 C9 BB B2 43 BF 23 56 1B 28 AA CD 6C C7 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 AB 7E CC 81 D2 E7 1B BA A3 5A 7D F4 -[2026-02-20T18:07:51.761356] LOG: [GPS SERVICE] Position stream fired: lat=47.36345, lon=-122.17707, accuracy=3.8m -[2026-02-20T18:07:52.573969] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:07:52.574158] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:07:52.604865] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:52.664578] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 2e 0b 00 00 00 83 23 00 00 -[2026-02-20T18:07:52.664710] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:52.664729] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:07:53.059808] LOG: [CONN] Frame received (87 bytes): 88 30 ca 15 21 cc 9b e8 86 2b 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2b 86 c7 db cc 81 d2 e7 1b ba a3 5a e5 74 50 94 d6 fa c1 02 94 d8 30 7a 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 0c 5d bd bd ed 5a fe 86 02 c2 4a 0e d9 b9 -[2026-02-20T18:07:53.059923] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:53.059948] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:53.060007] LOG: [RX PARSE] RAW Packet (84 bytes): 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 -[2026-02-20T18:07:53.060026] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:53.060036] LOG: [RX PARSE] Path length offset: 1, Path length: 33 -[2026-02-20T18:07:53.060065] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-54, payload=49 bytes -[2026-02-20T18:07:53.060078] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 -[2026-02-20T18:07:53.060090] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:53.060101] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:53.060111] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 9B -[2026-02-20T18:07:53.060171] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:53.060181] LOG: [RX FILTER] Raw packet (84 bytes): 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 -[2026-02-20T18:07:53.060199] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 12.0 -[2026-02-20T18:07:53.060208] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:07:53.060216] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:53.060228] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:07:53.060239] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:07:53.060248] LOG: [RX FILTER] Encrypted message: 46 bytes -[2026-02-20T18:07:53.060261] LOG: [CRYPTO] Decrypting message (46 bytes) -[2026-02-20T18:07:53.060396] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:53.060443] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:07:53.060636] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:07:53.060730] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:07:53.060739] LOG: [RX LOG] Dropped packet hex: 15 21 CC 9B E8 86 2B 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 2B 86 C7 DB CC 81 D2 E7 1B BA A3 5A E5 74 50 94 D6 FA C1 02 94 D8 30 7A 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 0C 5D BD BD ED 5A FE 86 02 C2 4A 0E D9 B9 -[2026-02-20T18:07:57.602850] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:07:57.602918] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:07:57.766635] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:07:57.766694] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:07:57.766700] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:07:57.766704] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:07:57.821184] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff ca 30 0b 00 00 00 84 23 00 00 -[2026-02-20T18:07:57.821240] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:07:57.821248] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:07:59.146048] LOG: [CONN] Frame received (143 bytes): 88 32 bd 11 07 07 2b 83 4f 50 7e cc c0 de cc 5a 28 67 eb da 4e 0d 8b ef 79 30 b0 66 4d c4 9f 14 6f 13 b7 3f 65 d4 f0 47 37 3b 35 a9 84 fb 4c 66 71 a2 5b 45 4c cb b1 42 84 47 99 a4 ce fb 96 8f 7f ed 72 ed a0 a9 e8 6e 87 0b e2 6a 0d 4a e3 95 80 97 22 a9 2b 91 19 b0 44 8e d9 f3 a1 ea 04 97 1c 38 51 70 db 05 d5 af f9 f9 ec c7 c7 8a d0 0e 92 04 9a d7 02 8c 96 b7 f8 4b 69 72 6b 6c 61 6e 64 20 48 69 67 68 6c 61 6e 64 73 20 e2 98 80 -[2026-02-20T18:07:59.146104] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:59.146115] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:59.146139] LOG: [RX PARSE] RAW Packet (140 bytes): 11 07 07 2B 83 4F 50 7E CC C0 DE CC 5A 28 67 EB DA 4E 0D 8B EF 79 30 B0 66 4D C4 9F 14 6F 13 B7 3F 65 D4 F0 47 37 3B 35 A9 84 FB 4C 66 71 A2 5B 45 4C CB B1 42 84 47 99 A4 CE FB 96 8F 7F ED 72 ED A0 A9 E8 6E 87 0B E2 6A 0D 4A E3 95 80 97 22 A9 2B 91 19 B0 44 8E D9 F3 A1 EA 04 97 1C 38 51 70 DB 05 D5 AF F9 F9 EC C7 C7 8A D0 0E 92 04 9A D7 02 8C 96 B7 F8 4B 69 72 6B 6C 61 6E 64 20 48 69 67 68 6C 61 6E 64 73 20 E2 98 80 -[2026-02-20T18:07:59.146145] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:07:59.146149] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:07:59.146156] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=7, firstHop=0x07, lastHop=0xcc, SNR=12.5, RSSI=-67, payload=131 bytes -[2026-02-20T18:07:59.146161] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=7 -[2026-02-20T18:07:59.146164] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:59.146166] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:59.146190] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:59.146192] LOG: [RX FILTER] Raw packet (140 bytes): 11 07 07 2B 83 4F 50 7E CC C0 DE CC 5A 28 67 EB DA 4E 0D 8B EF 79 30 B0 66 4D C4 9F 14 6F 13 B7 3F 65 D4 F0 47 37 3B 35 A9 84 FB 4C 66 71 A2 5B 45 4C CB B1 42 84 47 99 A4 CE FB 96 8F 7F ED 72 ED A0 A9 E8 6E 87 0B E2 6A 0D 4A E3 95 80 97 22 A9 2B 91 19 B0 44 8E D9 F3 A1 EA 04 97 1C 38 51 70 DB 05 D5 AF F9 F9 EC C7 C7 8A D0 0E 92 04 9A D7 02 8C 96 B7 F8 4B 69 72 6B 6C 61 6E 64 20 48 69 67 68 6C 61 6E 64 73 20 E2 98 80 -[2026-02-20T18:07:59.146212] LOG: [RX FILTER] Header: 0x11 | PathLength: 7 | SNR: 12.5 -[2026-02-20T18:07:59.146217] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) -[2026-02-20T18:07:59.146219] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:07:59.146221] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:07:59.146224] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:07:59.146266] LOG: [RX FILTER] ADVERT name extracted: "Kirkland Highlands ☀" (20 chars) -[2026-02-20T18:07:59.146273] LOG: [RX FILTER] ADVERT name printable ratio: 95.0% -[2026-02-20T18:07:59.146275] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Kirkland Highlands ☀") -[2026-02-20T18:07:59.146281] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=7 -[2026-02-20T18:07:59.146283] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:07:59.146286] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:07:59.146292] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:07:59.146296] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:07:59.146301] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:07:59.146305] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:07:59.146311] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36345,-122.17707 (batch tracking: 1 repeaters, rxCount: 26) -[2026-02-20T18:07:59.146317] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:07:59.146324] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:07:59.146432] LOG: [CONN] Frame received (148 bytes): 8a c0 de cc 5a 28 67 eb da 4e 0d 8b ef 79 30 b0 66 4d c4 9f 14 6f 13 b7 3f 65 d4 f0 47 37 3b 35 a9 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4b 69 72 6b 6c 61 6e 64 20 48 69 67 68 6c 61 6e 64 73 20 e2 98 80 00 00 00 00 00 00 00 00 00 00 84 fb 4c 66 04 9a d7 02 8c 96 b7 f8 7d 13 99 69 -[2026-02-20T18:07:59.146437] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:07:59.146440] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:07:59.146575] LOG: [CONN] Frame received (108 bytes): 88 31 bf 15 2a 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 20 20 20 20 75 68 26 07 f4 f1 fd 3e 0c 9f 7b fa 92 6e 6b ef fc 7a 08 24 07 f4 53 7e cc 91 bf 46 dd fc fa 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e 0e fc 12 35 7c ab 31 dc 96 77 86 -[2026-02-20T18:07:59.146580] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:07:59.146583] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:07:59.146600] LOG: [RX PARSE] RAW Packet (105 bytes): 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 -[2026-02-20T18:07:59.146602] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:07:59.146606] LOG: [RX PARSE] Path length offset: 1, Path length: 42 -[2026-02-20T18:07:59.146611] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=42, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-65, payload=61 bytes -[2026-02-20T18:07:59.146615] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=42 -[2026-02-20T18:07:59.146617] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:07:59.146618] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:07:59.146634] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:07:59.146637] LOG: [RX FILTER] Raw packet (105 bytes): 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 -[2026-02-20T18:07:59.146641] LOG: [RX FILTER] Header: 0x15 | PathLength: 42 | SNR: 12.25 -[2026-02-20T18:07:59.146646] LOG: [RX FILTER] ✓ RSSI OK (-65 < -30) -[2026-02-20T18:07:59.146647] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:07:59.146649] LOG: [RX FILTER] Channel hash: 0x91 -[2026-02-20T18:07:59.146653] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x91 -[2026-02-20T18:07:59.146670] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:07:59.146672] LOG: [RX LOG] Dropped packet hex: 15 2A 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 F4 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E 0E FC 12 35 7C AB 31 DC 96 77 86 -[2026-02-20T18:08:02.179083] LOG: [CONN] Frame received (68 bytes): 88 31 bb 15 0c 59 28 59 c9 ab 5a be 7a 18 7e 9b cc 6f ff 19 39 16 8f 78 1c 0c 1c b1 77 b3 09 a7 75 e3 07 6e b7 bc d1 fa d7 52 17 61 0f 04 46 72 8f 56 5e 7e 8d 6f 4d f4 55 5f 6f 11 f0 93 c8 9a d1 aa 35 80 -[2026-02-20T18:08:02.179124] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:02.179156] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:02.179205] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 -[2026-02-20T18:08:02.179218] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:02.179229] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:08:02.179246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x59, lastHop=0xcc, SNR=12.25, RSSI=-69, payload=51 bytes -[2026-02-20T18:08:02.179260] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:08:02.179269] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:02.179276] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:02.179322] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:02.179340] LOG: [RX FILTER] Raw packet (65 bytes): 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 -[2026-02-20T18:08:02.179353] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 -[2026-02-20T18:08:02.179367] LOG: [RX FILTER] ✓ RSSI OK (-69 < -30) -[2026-02-20T18:08:02.179376] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:02.179384] LOG: [RX FILTER] Channel hash: 0x6f -[2026-02-20T18:08:02.179396] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x6f -[2026-02-20T18:08:02.179534] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:08:02.179574] LOG: [RX LOG] Dropped packet hex: 15 0C 59 28 59 C9 AB 5A BE 7A 18 7E 9B CC 6F FF 19 39 16 8F 78 1C 0C 1C B1 77 B3 09 A7 75 E3 07 6E B7 BC D1 FA D7 52 17 61 0F 04 46 72 8F 56 5E 7E 8D 6F 4D F4 55 5F 6F 11 F0 93 C8 9A D1 AA 35 80 -[2026-02-20T18:08:02.602710] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:02.692089] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bb 31 0b 00 00 00 85 23 00 00 -[2026-02-20T18:08:02.692196] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:02.692211] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:05.207801] LOG: [CONN] Frame received (83 bytes): 88 32 be 15 0b 8d 82 bf 56 1b ab 9e 50 7a 7e cc 81 47 73 b0 cd af 51 79 cc 8f 68 40 9b b7 bb df 60 9b 1f 9d d5 0e c3 14 35 6f 11 8a 89 39 5d 86 b0 8a a5 87 10 e7 16 c2 1c 3c a9 be e9 c2 de d6 69 33 4e 75 76 f6 ba 22 fa b0 40 3b 2a 4d 95 e5 2b 5e 5d -[2026-02-20T18:08:05.207972] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:05.208004] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:05.208091] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0B 8D 82 BF 56 1B AB 9E 50 7A 7E CC 81 47 73 B0 CD AF 51 79 CC 8F 68 40 9B B7 BB DF 60 9B 1F 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 87 10 E7 16 C2 1C 3C A9 BE E9 C2 DE D6 69 33 4E 75 76 F6 BA 22 FA B0 40 3B 2A 4D 95 E5 2B 5E 5D -[2026-02-20T18:08:05.208111] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:05.208128] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:08:05.208161] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x8d, lastHop=0xcc, SNR=12.5, RSSI=-66, payload=67 bytes -[2026-02-20T18:08:05.208181] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:08:05.208196] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:05.208209] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:05.208289] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:05.208301] LOG: [RX FILTER] Raw packet (80 bytes): 15 0B 8D 82 BF 56 1B AB 9E 50 7A 7E CC 81 47 73 B0 CD AF 51 79 CC 8F 68 40 9B B7 BB DF 60 9B 1F 9D D5 0E C3 14 35 6F 11 8A 89 39 5D 86 B0 8A A5 87 10 E7 16 C2 1C 3C A9 BE E9 C2 DE D6 69 33 4E 75 76 F6 BA 22 FA B0 40 3B 2A 4D 95 E5 2B 5E 5D -[2026-02-20T18:08:05.208325] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 -[2026-02-20T18:08:05.208342] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) -[2026-02-20T18:08:05.208354] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:05.208369] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:08:05.208382] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:08:05.208407] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:08:05.208419] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:08:05.208515] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:08:05.208688] LOG: [RX FILTER] Decrypted message (58 chars): "VA7DDU - T1000-E: @[MapperBot] 48.99648, -123.82217 [0.3w]" -[2026-02-20T18:08:05.208712] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:08:05.208730] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:08:05.208762] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=11 -[2026-02-20T18:08:05.208776] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:05.208793] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.5, new=12.5 -[2026-02-20T18:08:05.208821] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:05.208840] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.5, current_best=12.5 -[2026-02-20T18:08:05.209285] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:08:05.209298] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:08:05.209323] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:08:06.247856] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:08:06.247996] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:08:06.248025] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:08:06.248061] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:08:06.248102] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36345, -122.17707 [0.3w]" -[2026-02-20T18:08:06.248112] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:08:06.248119] LOG: [TX LOG] Payload: "@[MapperBot] 47.36345, -122.17707 [0.3w]" -[2026-02-20T18:08:06.248134] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:08:06.248144] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:08:06.248166] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:08:06.248174] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:08:06.248190] LOG: [CONN] Sending ping: @[MapperBot] 47.36345, -122.17707 [0.3w] -[2026-02-20T18:08:06.314911] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:08:06.314961] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:08:06.314974] LOG: [CONN] Received OK response -[2026-02-20T18:08:07.573781] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:08:07.573893] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:08:07.602920] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:07.724466] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 32 0b 00 00 00 85 23 00 00 -[2026-02-20T18:08:07.724607] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:07.724633] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:08.452397] LOG: [CONN] Frame received (73 bytes): 88 32 bc 15 01 cc 81 1e d1 16 ff 6a 1c bb 92 54 81 69 10 f6 8d 6a 8d bb ae 17 5a e3 50 16 bb 9d 6c 09 73 f7 8a d9 42 f1 e6 f7 93 92 27 66 39 09 af 0e 95 f7 97 ce 73 73 e4 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:08:08.452554] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:08.452584] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:08.452654] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1E D1 16 FF 6A 1C BB 92 54 81 69 10 F6 8D 6A 8D BB AE 17 5A E3 50 16 BB 9D 6C 09 73 F7 8A D9 42 F1 E6 F7 93 92 27 66 39 09 AF 0E 95 F7 97 CE 73 73 E4 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:08:08.452675] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:08.452686] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:08:08.452714] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-68, payload=67 bytes -[2026-02-20T18:08:08.452730] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:08:08.452740] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:08:08.452758] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-68 -[2026-02-20T18:08:08.452769] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:08:08.452780] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:08:08.452797] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:08.452807] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:08.452825] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:08:09.316800] LOG: [PING] Ping sent successfully -[2026-02-20T18:08:10.183708] LOG: [CONN] Frame received (136 bytes): 88 34 bd 11 0c 11 99 b1 c4 a5 5f 0a 21 e0 cf 7e cc fe 41 d5 5b db 3f 70 63 44 3d cb 58 14 03 b9 4d a6 ea c0 07 7b ea 20 f3 8d 49 a4 00 48 40 ac 75 87 5b 08 00 9a 94 c1 89 32 ae 09 f8 60 d8 48 62 9d 71 c3 12 25 f2 1b 37 9b e0 d3 7f 08 90 dc ff 79 23 33 d7 eb 1b ae 9a 08 4e 30 da 1d 9b 6c b3 f2 3d d1 c8 1b 07 ad e4 e9 84 08 c2 5d ed 9a 53 e1 95 07 0f 92 52 a6 d7 02 0a b2 b4 f8 42 72 65 61 64 68 65 61 64 73 -[2026-02-20T18:08:10.183898] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:10.183930] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:10.184063] LOG: [RX PARSE] RAW Packet (133 bytes): 11 0C 11 99 B1 C4 A5 5F 0A 21 E0 CF 7E CC FE 41 D5 5B DB 3F 70 63 44 3D CB 58 14 03 B9 4D A6 EA C0 07 7B EA 20 F3 8D 49 A4 00 48 40 AC 75 87 5B 08 00 9A 94 C1 89 32 AE 09 F8 60 D8 48 62 9D 71 C3 12 25 F2 1B 37 9B E0 D3 7F 08 90 DC FF 79 23 33 D7 EB 1B AE 9A 08 4E 30 DA 1D 9B 6C B3 F2 3D D1 C8 1B 07 AD E4 E9 84 08 C2 5D ED 9A 53 E1 95 07 0F 92 52 A6 D7 02 0A B2 B4 F8 42 72 65 61 64 68 65 61 64 73 -[2026-02-20T18:08:10.184092] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:08:10.184109] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:08:10.184144] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=12, firstHop=0x11, lastHop=0xcc, SNR=13.0, RSSI=-67, payload=119 bytes -[2026-02-20T18:08:10.184164] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=12 -[2026-02-20T18:08:10.184175] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:08:10.184187] LOG: [TX LOG] Processing rx_log entry: SNR=13.0, RSSI=-67 -[2026-02-20T18:08:10.184203] LOG: [TX LOG] Ignoring: header validation failed (header=0x11) -[2026-02-20T18:08:10.184216] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:10.184231] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:10.184367] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:10.184379] LOG: [RX FILTER] Raw packet (133 bytes): 11 0C 11 99 B1 C4 A5 5F 0A 21 E0 CF 7E CC FE 41 D5 5B DB 3F 70 63 44 3D CB 58 14 03 B9 4D A6 EA C0 07 7B EA 20 F3 8D 49 A4 00 48 40 AC 75 87 5B 08 00 9A 94 C1 89 32 AE 09 F8 60 D8 48 62 9D 71 C3 12 25 F2 1B 37 9B E0 D3 7F 08 90 DC FF 79 23 33 D7 EB 1B AE 9A 08 4E 30 DA 1D 9B 6C B3 F2 3D D1 C8 1B 07 AD E4 E9 84 08 C2 5D ED 9A 53 E1 95 07 0F 92 52 A6 D7 02 0A B2 B4 F8 42 72 65 61 64 68 65 61 64 73 -[2026-02-20T18:08:10.184406] LOG: [RX FILTER] Header: 0x11 | PathLength: 12 | SNR: 13.0 -[2026-02-20T18:08:10.184424] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) -[2026-02-20T18:08:10.184436] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:08:10.184447] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:08:10.184461] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:08:10.184570] LOG: [RX FILTER] ADVERT name extracted: "Breadheads" (10 chars) -[2026-02-20T18:08:10.184586] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:08:10.184612] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Breadheads") -[2026-02-20T18:08:10.184632] LOG: [RX LOG] Packet heard via last hop: CC, SNR=13.0, path_length=12 -[2026-02-20T18:08:10.184648] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:10.184664] LOG: [RX BATCH] Better SNR for repeater CC: 12.5 -> 13.0 -[2026-02-20T18:08:10.184686] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:10.184706] LOG: [APP] Immediate RX observation: repeater=CC, snr=13.0, location=47.36345,-122.17707 -[2026-02-20T18:08:10.184728] LOG: [APP] Current batch tracking: 1 repeaters: {CC} -[2026-02-20T18:08:10.184741] LOG: [APP] Repeater CC already has pin in current batch, SNR will update on flush if better -[2026-02-20T18:08:10.184756] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=13.0, location=47.36345,-122.17707 -[2026-02-20T18:08:11.248986] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:08:12.603508] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:12.796135] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bd 34 0b 00 00 00 86 23 00 00 -[2026-02-20T18:08:12.796291] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:12.796311] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:14.235747] LOG: [CONN] Frame received (110 bytes): 88 30 bb 15 37 7e 6b 22 6e 6b ef 7e 75 20 20 20 20 20 20 20 20 20 75 68 26 07 f4 f1 fd 3e 0c 9f 7b fa 92 6e 6b ef fc 7a 08 24 07 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7e cc 91 bf 46 dd fc fa 3f d8 98 8a 7c 57 b2 15 37 cb a6 e2 ef 85 b3 c2 65 5e 1b c6 ce 5f 4d f4 9b cc 54 f6 1a d6 64 7f 9a 6b 0d a9 6c 5c ad 55 f2 9a 2f 4e -[2026-02-20T18:08:14.235831] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:14.235845] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:14.235876] LOG: [RX PARSE] RAW Packet (107 bytes): 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E -[2026-02-20T18:08:14.235883] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:14.235890] LOG: [RX PARSE] Path length offset: 1, Path length: 55 -[2026-02-20T18:08:14.235899] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=55, firstHop=0x7e, lastHop=0xcc, SNR=12.0, RSSI=-69, payload=50 bytes -[2026-02-20T18:08:14.235906] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=55 -[2026-02-20T18:08:14.235909] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:14.235913] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:14.235944] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:14.235949] LOG: [RX FILTER] Raw packet (107 bytes): 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E -[2026-02-20T18:08:14.235958] LOG: [RX FILTER] Header: 0x15 | PathLength: 55 | SNR: 12.0 -[2026-02-20T18:08:14.235965] LOG: [RX FILTER] ✓ RSSI OK (-69 < -30) -[2026-02-20T18:08:14.235968] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:14.235971] LOG: [RX FILTER] Channel hash: 0x91 -[2026-02-20T18:08:14.235978] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x91 -[2026-02-20T18:08:14.236016] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:08:14.236019] LOG: [RX LOG] Dropped packet hex: 15 37 7E 6B 22 6E 6B EF 7E 75 20 20 20 20 20 20 20 20 20 75 68 26 07 F4 F1 FD 3E 0C 9F 7B FA 92 6E 6B EF FC 7A 08 24 07 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E CC 91 BF 46 DD FC FA 3F D8 98 8A 7C 57 B2 15 37 CB A6 E2 EF 85 B3 C2 65 5E 1B C6 CE 5F 4D F4 9B CC 54 F6 1A D6 64 7F 9A 6B 0D A9 6C 5C AD 55 F2 9A 2F 4E -[2026-02-20T18:08:14.317657] LOG: [PING] RX listening window ended -[2026-02-20T18:08:14.317758] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:08:14.317787] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:08:14.317836] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:08:14.317844] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:08:14.317855] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:08:14.317871] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:08:14.317880] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:08:14.318224] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:08:16.307329] LOG: [CONN] Frame received (47 bytes): 88 31 bd 15 07 4e 1f 9c fb 23 7e cc ca 7d d6 66 66 c6 6b 4b 77 2e 74 a2 50 ea 56 39 7e 7c 2f 3c ed 79 5e e8 65 99 17 c2 28 f1 67 51 79 48 9b -[2026-02-20T18:08:16.307378] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:16.307421] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:16.307471] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 4E 1F 9C FB 23 7E CC CA 7D D6 66 66 C6 6B 4B 77 2E 74 A2 50 EA 56 39 7E 7C 2F 3C ED 79 5E E8 65 99 17 C2 28 F1 67 51 79 48 9B -[2026-02-20T18:08:16.307490] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:16.307502] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:08:16.307529] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x4e, lastHop=0xcc, SNR=12.25, RSSI=-67, payload=35 bytes -[2026-02-20T18:08:16.307544] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:08:16.307554] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:16.307570] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:16.307616] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:16.307628] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 4E 1F 9C FB 23 7E CC CA 7D D6 66 66 C6 6B 4B 77 2E 74 A2 50 EA 56 39 7E 7C 2F 3C ED 79 5E E8 65 99 17 C2 28 F1 67 51 79 48 9B -[2026-02-20T18:08:16.307650] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 -[2026-02-20T18:08:16.307664] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) -[2026-02-20T18:08:16.307679] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:16.307691] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:08:16.307703] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:08:16.307719] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:08:16.307731] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:08:16.307805] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:08:16.307976] LOG: [RX FILTER] Decrypted message (15 chars): "DieterPibbs1: P" -[2026-02-20T18:08:16.307999] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:08:16.308015] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:08:16.308156] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=7 -[2026-02-20T18:08:16.308169] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:16.308187] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=13.0, new=12.25 -[2026-02-20T18:08:16.308214] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:16.308232] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=13.0 -[2026-02-20T18:08:17.605077] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:17.715740] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bd 31 0b 00 00 00 86 23 00 00 -[2026-02-20T18:08:17.715865] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:17.715890] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:19.320347] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:08:19.320533] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:08:19.320549] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:08:19.771810] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:08:19.771879] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:08:19.771891] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771639999} -[2026-02-20T18:08:19.771909] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:08:19.771922] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:08:19.772257] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:08:19.772270] LOG: [APP] Upload success: +1 items (total: 39) -[2026-02-20T18:08:21.139015] LOG: [CONN] Frame received (140 bytes): 88 33 bf 15 04 01 e0 7e cc ca 18 f5 b6 4e 6b d6 15 ad 8d 9c b6 ad 0b 38 95 b5 98 11 0f bf fa df bb eb 0f 98 56 38 9c a7 76 04 81 8e c9 30 07 53 db ee 1d a2 b1 c4 9f 9b 46 a2 91 c4 c1 9f 02 66 e5 1c 7c d9 d5 ac 33 20 10 8a a1 52 f5 fa d0 55 38 e2 28 ae f5 7f 1f 29 aa 25 2d 6c eb 62 f6 aa 81 ac bd 36 6d 30 1b 69 f6 b8 79 cd 79 8d 0f c7 0b 15 14 ef d5 23 cd 08 50 1c 41 98 91 bd ad 5b c7 86 29 86 b9 94 ee ad ba 0a 11 ba -[2026-02-20T18:08:21.139435] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:21.139582] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:21.139748] LOG: [RX PARSE] RAW Packet (137 bytes): 15 04 01 E0 7E CC CA 18 F5 B6 4E 6B D6 15 AD 8D 9C B6 AD 0B 38 95 B5 98 11 0F BF FA DF BB EB 0F 98 56 38 9C A7 76 04 81 8E C9 30 07 53 DB EE 1D A2 B1 C4 9F 9B 46 A2 91 C4 C1 9F 02 66 E5 1C 7C D9 D5 AC 33 20 10 8A A1 52 F5 FA D0 55 38 E2 28 AE F5 7F 1F 29 AA 25 2D 6C EB 62 F6 AA 81 AC BD 36 6D 30 1B 69 F6 B8 79 CD 79 8D 0F C7 0B 15 14 EF D5 23 CD 08 50 1C 41 98 91 BD AD 5B C7 86 29 86 B9 94 EE AD BA 0A 11 BA -[2026-02-20T18:08:21.139775] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:21.139787] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:08:21.139824] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x01, lastHop=0xcc, SNR=12.75, RSSI=-65, payload=131 bytes -[2026-02-20T18:08:21.139838] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:08:21.139855] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:21.139866] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:21.139983] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:21.139995] LOG: [RX FILTER] Raw packet (137 bytes): 15 04 01 E0 7E CC CA 18 F5 B6 4E 6B D6 15 AD 8D 9C B6 AD 0B 38 95 B5 98 11 0F BF FA DF BB EB 0F 98 56 38 9C A7 76 04 81 8E C9 30 07 53 DB EE 1D A2 B1 C4 9F 9B 46 A2 91 C4 C1 9F 02 66 E5 1C 7C D9 D5 AC 33 20 10 8A A1 52 F5 FA D0 55 38 E2 28 AE F5 7F 1F 29 AA 25 2D 6C EB 62 F6 AA 81 AC BD 36 6D 30 1B 69 F6 B8 79 CD 79 8D 0F C7 0B 15 14 EF D5 23 CD 08 50 1C 41 98 91 BD AD 5B C7 86 29 86 B9 94 EE AD BA 0A 11 BA -[2026-02-20T18:08:21.140022] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.75 -[2026-02-20T18:08:21.140037] LOG: [RX FILTER] ✓ RSSI OK (-65 < -30) -[2026-02-20T18:08:21.140062] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:21.140073] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:08:21.140086] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:08:21.140103] LOG: [RX FILTER] Encrypted message: 128 bytes -[2026-02-20T18:08:21.140114] LOG: [CRYPTO] Decrypting message (128 bytes) -[2026-02-20T18:08:21.140245] LOG: [CRYPTO] Decrypted successfully (128 bytes) -[2026-02-20T18:08:21.140442] LOG: [RX FILTER] Decrypted message (110 chars): "HowlBot: 4E: The Winchester Re... 1F: First Hill Skyline 53..." -[2026-02-20T18:08:21.140466] LOG: [RX FILTER] Printable ratio: 86.4% (threshold: 60.0%) -[2026-02-20T18:08:21.140481] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:08:21.140514] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.75, path_length=4 -[2026-02-20T18:08:21.140525] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:21.140541] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=13.0, new=12.75 -[2026-02-20T18:08:21.140567] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:21.140586] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.75, current_best=13.0 -[2026-02-20T18:08:22.573650] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:08:22.573697] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:08:22.602627] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:22.692285] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bf 33 0b 00 00 00 87 23 00 00 -[2026-02-20T18:08:22.692344] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:22.692352] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:24.772786] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:08:27.603185] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:08:27.603308] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:27.703994] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:08:27.704092] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:08:27.704104] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:08:27.704119] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:08:27.762754] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bf 33 0b 00 00 00 87 23 00 00 -[2026-02-20T18:08:27.762917] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:27.762933] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:29.148233] LOG: [RX BATCH] 30s timeout triggered for repeater CC -[2026-02-20T18:08:29.148348] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:08:29.148359] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:08:29.148383] LOG: [RX BATCH] Posting repeater CC: snr=13.0, location=47.36345,-122.17707 -[2026-02-20T18:08:29.148392] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:08:29.148401] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=13.0, location=47.36345,-122.17707 -[2026-02-20T18:08:29.148417] LOG: [APP] Updated RX pin SNR for repeater=CC: 12.50 -> 13.00 -[2026-02-20T18:08:29.148426] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:08:29.148434] LOG: [APP] Added RX log entry: repeater=CC, snr=13.0, pathLen=12 -[2026-02-20T18:08:29.148527] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:08:31.010685] LOG: [CONN] Frame received (91 bytes): 88 32 be 15 03 c7 32 cc 81 05 3e 17 35 0d 38 ba b2 08 18 0d 27 2a 27 78 a6 ca 83 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb ee 9b 6c cd b2 47 a4 4f 16 93 41 e4 3c 59 25 af c1 be 63 10 2e 56 5c 90 59 11 86 e3 ed 70 13 49 -[2026-02-20T18:08:31.010838] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:31.010873] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:31.010955] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 C7 32 CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB EE 9B 6C CD B2 47 A4 4F 16 93 41 E4 3C 59 25 AF C1 BE 63 10 2E 56 5C 90 59 11 86 E3 ED 70 13 49 -[2026-02-20T18:08:31.010978] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:31.010989] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:08:31.011016] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xc7, lastHop=0xcc, SNR=12.5, RSSI=-66, payload=83 bytes -[2026-02-20T18:08:31.011032] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:08:31.011047] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:31.011059] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:31.011135] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:31.011151] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 C7 32 CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB EE 9B 6C CD B2 47 A4 4F 16 93 41 E4 3C 59 25 AF C1 BE 63 10 2E 56 5C 90 59 11 86 E3 ED 70 13 49 -[2026-02-20T18:08:31.011171] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 12.5 -[2026-02-20T18:08:31.011198] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) -[2026-02-20T18:08:31.011209] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:31.011219] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:08:31.011236] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:08:31.011248] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:08:31.011264] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:08:31.011364] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:08:31.011536] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.39640, -122.51882 [..." -[2026-02-20T18:08:31.011561] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:08:31.011576] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:08:31.011609] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.5, path_length=3 -[2026-02-20T18:08:31.011620] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:31.011637] LOG: [RX BATCH] First observation for repeater CC: SNR=12.5 -[2026-02-20T18:08:31.011659] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:08:31.011678] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:31.011703] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:08:31.011722] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:08:31.011746] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36345,-122.17707 (batch tracking: 1 repeaters, rxCount: 27) -[2026-02-20T18:08:31.011766] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:08:31.011790] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:08:31.012313] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:08:31.012327] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:08:31.012343] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:08:32.603251] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:32.714230] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 32 0b 00 00 00 87 23 00 00 -[2026-02-20T18:08:32.714392] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:32.714409] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:34.787712] LOG: [CONN] Frame received (44 bytes): 88 31 bd 15 04 41 32 9b cc ca 3a a8 5d ca 70 2f f8 c7 2a f9 17 c2 93 a5 03 91 d6 6c b3 75 70 b8 b8 82 de e7 68 f3 23 23 14 1b 2b be -[2026-02-20T18:08:34.787824] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:34.787845] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:34.787900] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 41 32 9B CC CA 3A A8 5D CA 70 2F F8 C7 2A F9 17 C2 93 A5 03 91 D6 6C B3 75 70 B8 B8 82 DE E7 68 F3 23 23 14 1B 2B BE -[2026-02-20T18:08:34.787909] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:34.787916] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:08:34.787936] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x41, lastHop=0xcc, SNR=12.25, RSSI=-67, payload=35 bytes -[2026-02-20T18:08:34.787944] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:08:34.787954] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:34.787961] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:34.787989] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:34.787998] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 41 32 9B CC CA 3A A8 5D CA 70 2F F8 C7 2A F9 17 C2 93 A5 03 91 D6 6C B3 75 70 B8 B8 82 DE E7 68 F3 23 23 14 1B 2B BE -[2026-02-20T18:08:34.788008] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.25 -[2026-02-20T18:08:34.788018] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) -[2026-02-20T18:08:34.788029] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:34.788036] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:08:34.788047] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:08:34.788054] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:08:34.788061] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:08:34.788106] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:08:34.788234] LOG: [RX FILTER] Decrypted message (13 chars): "Airhack: Path" -[2026-02-20T18:08:34.788251] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:08:34.788262] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:08:34.788283] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=4 -[2026-02-20T18:08:34.788290] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:08:34.788301] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.5, new=12.25 -[2026-02-20T18:08:34.788320] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:08:34.788332] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=12.5 -[2026-02-20T18:08:36.780132] LOG: [GPS SERVICE] Position stream fired: lat=47.36336, lon=-122.17682, accuracy=3.8m -[2026-02-20T18:08:36.780178] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:08:36.780198] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:08:36.780207] LOG: [RX BATCH] Distance check for repeater CC: 21.78m from first observation (threshold=25m) -[2026-02-20T18:08:36.780251] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:08:37.573839] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:08:37.574084] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:08:37.574097] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:08:37.575482] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:08:37.602891] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:37.693088] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff bd 31 0b 00 00 00 87 23 00 00 -[2026-02-20T18:08:37.693213] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:37.693239] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:08:38.047340] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:08:38.047432] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:08:38.047455] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640017} -[2026-02-20T18:08:38.047474] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:08:38.047493] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:08:38.047916] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:08:38.047934] LOG: [APP] Upload success: +1 items (total: 40) -[2026-02-20T18:08:40.635793] LOG: [CONN] Frame received (49 bytes): 88 30 c5 15 0b c7 7e 75 20 20 20 20 53 7e 9d cc 81 05 3e 17 35 0d 38 ba b2 08 18 0d 27 2a 27 78 a6 ca 83 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df -[2026-02-20T18:08:40.636002] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:40.636039] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:40.636103] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF -[2026-02-20T18:08:40.636118] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:40.636129] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:08:40.636173] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xc7, lastHop=0xcc, SNR=12.0, RSSI=-59, payload=33 bytes -[2026-02-20T18:08:40.636187] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:08:40.636203] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:40.636213] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:40.636260] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:08:40.636278] LOG: [RX FILTER] Raw packet (46 bytes): 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF -[2026-02-20T18:08:40.636294] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.0 -[2026-02-20T18:08:40.636314] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:08:40.636326] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:08:40.636336] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:08:40.636352] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:08:40.636365] LOG: [RX FILTER] Encrypted message: 30 bytes -[2026-02-20T18:08:40.636375] LOG: [CRYPTO] Decrypting message (30 bytes) -[2026-02-20T18:08:40.636558] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:08:40.636609] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:08:40.636847] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:08:40.636941] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:08:40.636966] LOG: [RX LOG] Dropped packet hex: 15 0B C7 7E 75 20 20 20 20 53 7E 9D CC 81 05 3E 17 35 0D 38 BA B2 08 18 0D 27 2A 27 78 A6 CA 83 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF -[2026-02-20T18:08:41.766274] LOG: [GPS SERVICE] Position stream fired: lat=47.36303, lon=-122.17596, accuracy=10.1m -[2026-02-20T18:08:41.766322] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:08:41.766334] LOG: [RX BATCH] Distance check for repeater CC: 96.40m from first observation (threshold=25m) -[2026-02-20T18:08:41.766339] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:08:41.766341] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:08:41.766349] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:08:41.766354] LOG: [RX BATCH] Posting repeater CC: snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:08:41.766357] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:08:41.766380] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.5, location=47.36345,-122.17707 -[2026-02-20T18:08:41.766385] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.50 <= pin 12.50 -[2026-02-20T18:08:41.766391] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:08:41.766395] LOG: [APP] Added RX log entry: repeater=CC, snr=12.5, pathLen=3 -[2026-02-20T18:08:41.766451] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:08:41.766456] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:08:42.602799] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:42.644762] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 30 0b 00 00 00 87 23 00 00 -[2026-02-20T18:08:42.644888] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:42.644904] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:43.049159] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:08:44.318975] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:08:44.319035] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:08:44.319042] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:08:44.319058] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:08:44.319073] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36303, -122.17596 [0.3w]" -[2026-02-20T18:08:44.319077] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:08:44.319081] LOG: [TX LOG] Payload: "@[MapperBot] 47.36303, -122.17596 [0.3w]" -[2026-02-20T18:08:44.319085] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:08:44.319088] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:08:44.319094] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:08:44.319096] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:08:44.319104] LOG: [CONN] Sending ping: @[MapperBot] 47.36303, -122.17596 [0.3w] -[2026-02-20T18:08:44.504072] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:08:44.504156] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:08:44.504166] LOG: [CONN] Received OK response -[2026-02-20T18:08:46.220704] LOG: [CONN] Frame received (73 bytes): 88 30 c3 15 01 cc 81 b9 c8 1c 26 12 b6 21 4b 75 33 29 42 28 28 b4 ae d2 3e 6d 72 46 cb 1c 13 83 2f 13 04 3d 8c 85 71 17 26 4e f5 41 2a 3a f0 4f ca 28 c7 82 b4 e9 9e 8d ce 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:08:46.220872] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:08:46.220903] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:08:46.220983] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 B9 C8 1C 26 12 B6 21 4B 75 33 29 42 28 28 B4 AE D2 3E 6D 72 46 CB 1C 13 83 2F 13 04 3D 8C 85 71 17 26 4E F5 41 2A 3A F0 4F CA 28 C7 82 B4 E9 9E 8D CE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:08:46.221004] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:08:46.221016] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:08:46.221045] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-61, payload=67 bytes -[2026-02-20T18:08:46.221059] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:08:46.221070] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:08:46.221087] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-61 -[2026-02-20T18:08:46.221099] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:08:46.221109] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:08:46.221129] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:08:46.221139] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:08:46.221153] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:08:46.753693] LOG: [GPS SERVICE] Position stream fired: lat=47.36273, lon=-122.17506, accuracy=3.8m -[2026-02-20T18:08:47.505017] LOG: [PING] Ping sent successfully -[2026-02-20T18:08:47.603957] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:47.770791] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:08:47.770853] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:47.770861] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:49.320737] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:08:51.764756] LOG: [GPS SERVICE] Position stream fired: lat=47.36233, lon=-122.17416, accuracy=3.8m -[2026-02-20T18:08:52.505872] LOG: [PING] RX listening window ended -[2026-02-20T18:08:52.506052] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:08:52.506080] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:08:52.506153] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:08:52.506168] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:08:52.506179] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:08:52.506203] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:08:52.506218] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:08:52.506610] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:08:52.573676] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:08:52.573855] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:08:52.573868] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:08:52.573882] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:08:52.577682] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:08:52.602801] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:52.783877] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:08:52.783949] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:52.783957] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:08:53.084037] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:08:53.084088] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:08:53.084097] LOG: [API] Response (200) in 0.51s: {"success":true,"expires_at":1771640032} -[2026-02-20T18:08:53.084106] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:08:53.084118] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:08:53.084848] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:08:53.084869] LOG: [APP] Upload success: +2 items (total: 42) -[2026-02-20T18:08:56.761688] LOG: [GPS SERVICE] Position stream fired: lat=47.36188, lon=-122.17324, accuracy=3.8m -[2026-02-20T18:08:57.508870] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:08:57.509085] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:08:57.604396] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:08:57.604583] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:08:57.794343] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:08:57.794465] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:08:57.794475] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:08:57.794495] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:08:57.855567] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:08:57.855702] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:08:57.855730] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:08:58.087297] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:09:01.784072] LOG: [GPS SERVICE] Position stream fired: lat=47.36128, lon=-122.17240, accuracy=3.8m -[2026-02-20T18:09:02.603025] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:02.712965] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:09:02.713026] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:02.713037] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:06.772021] LOG: [GPS SERVICE] Position stream fired: lat=47.36065, lon=-122.17161, accuracy=3.8m -[2026-02-20T18:09:07.580453] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:09:07.580610] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:09:07.603300] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:07.725309] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:09:07.725439] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:07.725465] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:11.753460] LOG: [GPS SERVICE] Position stream fired: lat=47.35995, lon=-122.17090, accuracy=3.8m -[2026-02-20T18:09:11.753514] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:09:11.753586] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:09:12.602908] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:12.735058] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:09:12.735116] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:12.735123] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:09:16.771635] LOG: [GPS SERVICE] Position stream fired: lat=47.35934, lon=-122.17006, accuracy=3.8m -[2026-02-20T18:09:17.603932] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:17.745385] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:09:17.745490] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:17.745510] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:21.764729] LOG: [GPS SERVICE] Position stream fired: lat=47.35889, lon=-122.16921, accuracy=3.8m -[2026-02-20T18:09:22.507198] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:09:22.511382] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:09:22.511529] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:09:22.511693] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:09:22.511834] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35889, -122.16921 [0.3w]" -[2026-02-20T18:09:22.511842] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:09:22.511858] LOG: [TX LOG] Payload: "@[MapperBot] 47.35889, -122.16921 [0.3w]" -[2026-02-20T18:09:22.511870] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:09:22.511914] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:09:22.511924] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:09:22.511926] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:09:22.511970] LOG: [CONN] Sending ping: @[MapperBot] 47.35889, -122.16921 [0.3w] -[2026-02-20T18:09:22.573948] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:09:22.574126] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:09:22.604848] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:22.639756] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:09:22.639872] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:09:22.639886] LOG: [CONN] Received OK response -[2026-02-20T18:09:22.691794] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0b 00 00 00 88 23 00 00 -[2026-02-20T18:09:22.691901] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:22.691917] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:23.207092] LOG: [CONN] Frame received (73 bytes): 88 31 c7 15 01 cc 81 00 65 30 16 44 58 60 e5 b1 6f ee 35 96 a3 49 6c 43 04 84 e6 4d 5e e9 25 12 5a a1 b7 f3 53 fc 00 09 13 36 18 09 a2 55 35 78 b1 14 51 5c 33 c1 f5 27 69 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:09:23.207221] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:09:23.207246] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:09:23.207301] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 00 65 30 16 44 58 60 E5 B1 6F EE 35 96 A3 49 6C 43 04 84 E6 4D 5E E9 25 12 5A A1 B7 F3 53 FC 00 09 13 36 18 09 A2 55 35 78 B1 14 51 5C 33 C1 F5 27 69 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:09:23.207316] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:09:23.207326] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:09:23.207350] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=67 bytes -[2026-02-20T18:09:23.207365] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:09:23.207372] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:09:23.207391] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 -[2026-02-20T18:09:23.207399] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:09:23.207407] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:09:23.207425] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:09:23.207433] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:09:23.207440] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:09:25.640368] LOG: [PING] Ping sent successfully -[2026-02-20T18:09:26.775778] LOG: [GPS SERVICE] Position stream fired: lat=47.35850, lon=-122.16826, accuracy=3.8m -[2026-02-20T18:09:27.515727] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:09:27.603162] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:09:27.603419] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:27.762959] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:09:27.763102] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:09:27.763121] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:09:27.763137] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:09:27.822483] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:27.822622] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:27.822639] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:30.641012] LOG: [PING] RX listening window ended -[2026-02-20T18:09:30.641216] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:09:30.641271] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:09:30.641368] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:09:30.641382] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:09:30.641401] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:09:30.641427] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:09:30.641443] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:09:30.660793] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:09:31.768739] LOG: [GPS SERVICE] Position stream fired: lat=47.35824, lon=-122.16740, accuracy=3.8m -[2026-02-20T18:09:32.602705] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:32.683925] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:32.684011] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:32.684023] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:35.661613] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:09:35.661701] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:09:35.661705] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:09:36.280947] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:09:36.280989] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:09:36.281008] LOG: [API] Response (200) in 0.62s: {"success":true,"expires_at":1771640076} -[2026-02-20T18:09:36.281028] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:09:36.281048] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:09:36.281910] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:09:36.281928] LOG: [APP] Upload success: +1 items (total: 43) -[2026-02-20T18:09:36.759853] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.16658, accuracy=3.8m -[2026-02-20T18:09:37.573894] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:09:37.574089] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:09:37.602829] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:37.694955] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:37.695109] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:37.695129] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:41.282955] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:09:41.778481] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.16609, accuracy=3.8m -[2026-02-20T18:09:41.778564] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:09:41.778584] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:09:42.603270] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:42.705300] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:42.705453] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:42.705473] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:47.605687] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:47.684226] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:47.684350] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:47.684369] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:52.573703] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:09:52.573776] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:09:52.603026] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:52.694636] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:52.694704] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:52.694715] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:09:57.602963] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:09:57.603166] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:09:57.735611] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:09:57.735737] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:09:57.735750] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:09:57.735768] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T18:09:57.793304] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:09:57.793485] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:09:57.793506] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:00.641669] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:10:00.641746] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:10:00.641757] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:10:00.641779] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:10:00.641800] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35803, -122.16609 [0.3w]" -[2026-02-20T18:10:00.641806] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:10:00.641810] LOG: [TX LOG] Payload: "@[MapperBot] 47.35803, -122.16609 [0.3w]" -[2026-02-20T18:10:00.641818] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:10:00.641822] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:10:00.641828] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:10:00.641834] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:10:00.641843] LOG: [CONN] Sending ping: @[MapperBot] 47.35803, -122.16609 [0.3w] -[2026-02-20T18:10:00.708993] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:10:00.709118] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:10:00.709132] LOG: [CONN] Received OK response -[2026-02-20T18:10:02.296256] LOG: [CONN] Frame received (73 bytes): 88 30 ce 15 01 cc 81 70 3e ed 82 c0 21 7e 14 da d3 8a e4 84 f6 f5 88 c1 17 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 9c 1c f5 18 f6 36 d2 69 b9 ae 92 be f8 43 96 bc 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:10:02.296289] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:10:02.296312] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:10:02.296344] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 70 3E ED 82 C0 21 7E 14 DA D3 8A E4 84 F6 F5 88 C1 17 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 9C 1C F5 18 F6 36 D2 69 B9 AE 92 BE F8 43 96 BC 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:10:02.296351] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:10:02.296358] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:10:02.296375] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-50, payload=67 bytes -[2026-02-20T18:10:02.296384] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:10:02.296390] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:10:02.296395] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-50 -[2026-02-20T18:10:02.296402] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:10:02.296407] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:10:02.296467] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:10:02.296472] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:10:02.296476] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:10:02.603842] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:02.651931] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:02.652009] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:02.652019] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:03.710945] LOG: [PING] Ping sent successfully -[2026-02-20T18:10:05.642595] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:10:06.766296] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.16579, accuracy=3.8m -[2026-02-20T18:10:07.573818] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:10:07.573968] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:10:07.603739] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:07.665080] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:07.665209] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:07.665235] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:08.711599] LOG: [PING] RX listening window ended -[2026-02-20T18:10:08.711658] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:10:08.711667] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:10:08.711697] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:10:08.711701] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:10:08.711705] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:10:08.711713] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:10:08.711717] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:10:08.712011] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:10:11.763251] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.16503, accuracy=16.6m -[2026-02-20T18:10:12.603095] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:12.674228] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 30 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:12.674336] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:12.674351] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:13.713852] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:10:13.714075] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:10:13.714094] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:10:14.253600] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:10:14.253641] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:10:14.253650] LOG: [API] Response (200) in 0.54s: {"success":true,"expires_at":1771640114} -[2026-02-20T18:10:14.253657] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:10:14.253668] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:10:14.253887] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:10:14.253895] LOG: [APP] Upload success: +1 items (total: 44) -[2026-02-20T18:10:16.020365] LOG: [CONN] Frame received (49 bytes): 88 31 cb 15 0a 7e 75 a6 20 20 53 a5 e8 9d cc ba 48 dd 91 cb 6a 46 d5 ec 39 eb 72 d4 5d 1b 3b 3f c0 8b e5 31 aa d6 53 b9 fe ea a8 64 d8 fd 8e c5 f9 -[2026-02-20T18:10:16.020522] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:10:16.020553] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:10:16.020620] LOG: [RX PARSE] RAW Packet (46 bytes): 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 -[2026-02-20T18:10:16.020635] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:10:16.020652] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:10:16.020676] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x7e, lastHop=0xcc, SNR=12.25, RSSI=-53, payload=34 bytes -[2026-02-20T18:10:16.020690] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:10:16.020705] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:10:16.020715] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:10:16.020761] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:10:16.020778] LOG: [RX FILTER] Raw packet (46 bytes): 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 -[2026-02-20T18:10:16.020794] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 -[2026-02-20T18:10:16.020813] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) -[2026-02-20T18:10:16.020825] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:10:16.020835] LOG: [RX FILTER] Channel hash: 0xba -[2026-02-20T18:10:16.020852] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba -[2026-02-20T18:10:16.020909] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:10:16.020925] LOG: [RX LOG] Dropped packet hex: 15 0A 7E 75 A6 20 20 53 A5 E8 9D CC BA 48 DD 91 CB 6A 46 D5 EC 39 EB 72 D4 5D 1B 3B 3F C0 8B E5 31 AA D6 53 B9 FE EA A8 64 D8 FD 8E C5 F9 -[2026-02-20T18:10:16.795798] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.16397, accuracy=3.8m -[2026-02-20T18:10:16.795838] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:10:16.795894] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:10:17.603254] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:17.713546] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:17.713672] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:17.713697] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:19.258979] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:10:21.790433] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.16277, accuracy=3.8m -[2026-02-20T18:10:22.574099] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:10:22.574265] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:10:22.603736] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:22.753516] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:22.753651] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:22.753670] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:27.100807] LOG: [GPS SERVICE] Position stream fired: lat=47.35792, lon=-122.16141, accuracy=3.8m -[2026-02-20T18:10:27.605284] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:10:27.605427] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:27.762158] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:10:27.762238] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:10:27.762251] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:10:27.762260] LOG: [CONN] Battery updated: 4059mV (88%) -[2026-02-20T18:10:27.823542] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cb 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:27.823689] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:27.823713] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:10:31.799520] LOG: [GPS SERVICE] Position stream fired: lat=47.35793, lon=-122.16014, accuracy=3.8m -[2026-02-20T18:10:32.602874] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:32.684220] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:32.684345] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:32.684370] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:36.765414] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.15879, accuracy=3.8m -[2026-02-20T18:10:37.573611] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:10:37.573677] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:10:37.602612] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:37.692701] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0c 00 00 00 88 23 00 00 -[2026-02-20T18:10:37.692754] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:37.692760] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:38.712957] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:10:38.713073] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:10:38.713083] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:10:38.713120] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:10:38.713147] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35795, -122.15879 [0.3w]" -[2026-02-20T18:10:38.713156] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:10:38.713160] LOG: [TX LOG] Payload: "@[MapperBot] 47.35795, -122.15879 [0.3w]" -[2026-02-20T18:10:38.713168] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:10:38.713177] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:10:38.713183] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:10:38.713188] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:10:38.713204] LOG: [CONN] Sending ping: @[MapperBot] 47.35795, -122.15879 [0.3w] -[2026-02-20T18:10:38.805507] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:10:38.805606] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:10:38.805621] LOG: [CONN] Received OK response -[2026-02-20T18:10:39.798987] LOG: [CONN] Frame received (73 bytes): 88 30 c4 15 01 cc 81 77 e9 2f 36 cf bd b7 2d 93 fb b0 81 39 1e 26 f8 1c 0e 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 5f 02 18 04 40 35 c7 8e 58 3e f2 ec 49 03 ca 3e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:10:39.799128] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:10:39.799157] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:10:39.799214] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 77 E9 2F 36 CF BD B7 2D 93 FB B0 81 39 1E 26 F8 1C 0E 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 5F 02 18 04 40 35 C7 8E 58 3E F2 EC 49 03 CA 3E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:10:39.799237] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:10:39.799245] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:10:39.799263] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes -[2026-02-20T18:10:39.799279] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:10:39.799556] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:10:39.799571] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-60 -[2026-02-20T18:10:39.799581] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:10:39.799589] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:10:39.799603] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:10:39.799610] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:10:39.799617] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:10:40.289127] LOG: [CONN] Frame received (44 bytes): 88 2e c4 15 04 ba 43 86 cc d9 5a 3b c9 49 08 78 94 b6 31 21 1e c8 3c bb 95 c1 49 36 e5 67 7d 32 6a 4f b7 dd 0e b4 c6 84 6a 19 12 b5 -[2026-02-20T18:10:40.289253] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:10:40.289277] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:10:40.289323] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 -[2026-02-20T18:10:40.289332] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:10:40.289341] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:10:40.289362] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xba, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=35 bytes -[2026-02-20T18:10:40.289373] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:10:40.289380] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:10:40.289387] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-60 -[2026-02-20T18:10:40.289395] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:10:40.289404] LOG: [TX LOG] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:10:40.289411] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xd9, expected=0x81 -[2026-02-20T18:10:40.289425] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:10:40.289433] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:10:40.289438] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:10:40.289467] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:10:40.289475] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 -[2026-02-20T18:10:40.289485] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 -[2026-02-20T18:10:40.289497] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:10:40.289505] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:10:40.289511] LOG: [RX FILTER] Channel hash: 0xd9 -[2026-02-20T18:10:40.289522] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xd9 -[2026-02-20T18:10:40.289554] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:10:40.289564] LOG: [RX LOG] Dropped packet hex: 15 04 BA 43 86 CC D9 5A 3B C9 49 08 78 94 B6 31 21 1E C8 3C BB 95 C1 49 36 E5 67 7D 32 6A 4F B7 DD 0E B4 C6 84 6A 19 12 B5 -[2026-02-20T18:10:41.768572] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.15743, accuracy=3.8m -[2026-02-20T18:10:41.805696] LOG: [PING] Ping sent successfully -[2026-02-20T18:10:42.602671] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:42.732320] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:10:42.732372] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:42.732378] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:10:43.713593] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:10:46.788265] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15609, accuracy=4.0m -[2026-02-20T18:10:46.806744] LOG: [PING] RX listening window ended -[2026-02-20T18:10:46.806858] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:10:46.806895] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:10:46.806957] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:10:46.806965] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:10:46.806977] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:10:46.807028] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:10:46.807038] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:10:46.818563] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:10:47.604447] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:47.742509] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:10:47.742599] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:47.742605] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:51.781100] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15471, accuracy=4.1m -[2026-02-20T18:10:51.781156] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:10:51.781235] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:10:51.821920] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:10:51.821989] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:10:51.821993] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:10:52.464149] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:10:52.464207] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:10:52.464214] LOG: [API] Response (200) in 0.64s: {"success":true,"expires_at":1771640152} -[2026-02-20T18:10:52.464225] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:10:52.464235] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:10:52.464933] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:10:52.464947] LOG: [APP] Upload success: +1 items (total: 45) -[2026-02-20T18:10:52.573918] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:10:52.574073] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:10:52.604328] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:52.755510] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:10:52.755669] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:52.755696] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:10:56.789783] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.15333, accuracy=3.8m -[2026-02-20T18:10:57.465857] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:10:57.602750] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:10:57.602833] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:10:57.761973] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:10:57.762005] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:10:57.762013] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:10:57.762019] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:10:57.822762] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:10:57.822813] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:10:57.822820] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:01.761072] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.15199, accuracy=3.8m -[2026-02-20T18:11:02.603259] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:02.711303] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:11:02.711358] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:02.711363] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:11:06.753474] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.15103, accuracy=3.8m -[2026-02-20T18:11:07.575905] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:11:07.576067] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:11:07.603152] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:07.722333] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:11:07.722417] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:07.722432] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:11:11.786411] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.15012, accuracy=3.8m -[2026-02-20T18:11:12.602925] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:12.732751] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:11:12.732905] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:12.732924] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:16.782083] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14910, accuracy=3.8m -[2026-02-20T18:11:16.807679] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:11:16.807798] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:11:16.807809] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:11:16.807839] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:11:16.807867] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35796, -122.14910 [0.3w]" -[2026-02-20T18:11:16.807879] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:11:16.807884] LOG: [TX LOG] Payload: "@[MapperBot] 47.35796, -122.14910 [0.3w]" -[2026-02-20T18:11:16.807892] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:11:16.807905] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:11:16.807912] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:11:16.807918] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:11:16.807934] LOG: [CONN] Sending ping: @[MapperBot] 47.35796, -122.14910 [0.3w] -[2026-02-20T18:11:17.022894] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:11:17.023041] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:11:17.023056] LOG: [CONN] Received OK response -[2026-02-20T18:11:17.604221] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:17.683112] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0c 00 00 00 89 23 00 00 -[2026-02-20T18:11:17.683236] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:17.683255] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:18.765455] LOG: [CONN] Frame received (73 bytes): 88 2f c3 15 01 cc 81 7e 8e 32 03 86 48 7d 53 35 9a e1 9b 4f ed 26 21 6f 6a 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 b6 a4 30 34 b4 c2 37 bc b1 e2 5d 46 bf 94 a3 85 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:11:18.765626] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:11:18.765639] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:11:18.765666] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 7E 8E 32 03 86 48 7D 53 35 9A E1 9B 4F ED 26 21 6F 6A 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 B6 A4 30 34 B4 C2 37 BC B1 E2 5D 46 BF 94 A3 85 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:11:18.765674] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:11:18.765678] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:11:18.765693] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=67 bytes -[2026-02-20T18:11:18.765699] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:11:18.765702] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:11:18.765709] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-61 -[2026-02-20T18:11:18.765712] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:11:18.765716] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:11:18.765723] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:11:18.765726] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:11:18.765730] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:11:19.992959] LOG: [PING] Ping sent successfully -[2026-02-20T18:11:21.243862] LOG: [CONN] Frame received (55 bytes): 88 2f c2 15 21 75 b0 0a ab 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0a ab 7e db cc ba 13 7e e4 b3 61 3d 2e 96 3d 5a 80 8f 8c c0 27 21 -[2026-02-20T18:11:21.244017] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:11:21.244048] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:11:21.244105] LOG: [RX PARSE] RAW Packet (52 bytes): 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 -[2026-02-20T18:11:21.244126] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:11:21.244137] LOG: [RX PARSE] Path length offset: 1, Path length: 33 -[2026-02-20T18:11:21.244164] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0x75, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=17 bytes -[2026-02-20T18:11:21.244178] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 -[2026-02-20T18:11:21.244193] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:11:21.244208] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-62 -[2026-02-20T18:11:21.244218] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:11:21.244237] LOG: [TX LOG] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:11:21.244249] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xba, expected=0x81 -[2026-02-20T18:11:21.244260] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:11:21.244275] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:11:21.244285] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:11:21.244337] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:11:21.244353] LOG: [RX FILTER] Raw packet (52 bytes): 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 -[2026-02-20T18:11:21.244369] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 11.75 -[2026-02-20T18:11:21.244386] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:11:21.244397] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:11:21.244407] LOG: [RX FILTER] Channel hash: 0xba -[2026-02-20T18:11:21.244424] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba -[2026-02-20T18:11:21.244497] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:11:21.244509] LOG: [RX LOG] Dropped packet hex: 15 21 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 26 07 0A AB 7E DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 27 21 -[2026-02-20T18:11:21.768475] LOG: [CONN] Frame received (54 bytes): 88 31 c4 15 22 75 b0 0a ab 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 a5 c7 32 db cc ba 13 7e e4 b3 61 3d 2e 96 3d 5a 80 8f 8c c0 -[2026-02-20T18:11:21.768521] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:11:21.768551] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:11:21.768596] LOG: [RX PARSE] RAW Packet (51 bytes): 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 -[2026-02-20T18:11:21.768607] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:11:21.768621] LOG: [RX PARSE] Path length offset: 1, Path length: 34 -[2026-02-20T18:11:21.768645] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=34, firstHop=0x75, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=15 bytes -[2026-02-20T18:11:21.768659] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=34 -[2026-02-20T18:11:21.768668] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:11:21.768676] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-60 -[2026-02-20T18:11:21.768688] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:11:21.768699] LOG: [TX LOG] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:11:21.768707] LOG: [TX LOG] Message correlation check: packet_channel_hash=0xba, expected=0x81 -[2026-02-20T18:11:21.768719] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:11:21.768814] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:11:21.768828] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:11:21.768869] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:11:21.768877] LOG: [RX FILTER] Raw packet (51 bytes): 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 -[2026-02-20T18:11:21.768892] LOG: [RX FILTER] Header: 0x15 | PathLength: 34 | SNR: 12.25 -[2026-02-20T18:11:21.768901] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:11:21.768912] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:11:21.768920] LOG: [RX FILTER] Channel hash: 0xba -[2026-02-20T18:11:21.768928] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xba -[2026-02-20T18:11:21.768983] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:11:21.768995] LOG: [RX LOG] Dropped packet hex: 15 22 75 B0 0A AB 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 07 A5 C7 32 DB CC BA 13 7E E4 B3 61 3D 2E 96 3D 5A 80 8F 8C C0 -[2026-02-20T18:11:21.791918] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.14803, accuracy=3.8m -[2026-02-20T18:11:21.791980] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:11:21.792002] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:11:21.808676] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:11:22.573785] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:11:22.573979] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:11:22.603353] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:22.724317] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c4 31 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:22.724423] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:22.724437] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:11:24.995128] LOG: [PING] RX listening window ended -[2026-02-20T18:11:24.995313] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:11:24.995335] LOG: [GRAPH] Recorded txFail event at -120dBm -[2026-02-20T18:11:24.995431] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:11:24.995485] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:11:24.995495] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:11:24.995518] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:11:24.995531] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:11:24.996271] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:11:26.778793] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14688, accuracy=3.8m -[2026-02-20T18:11:27.602870] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:11:27.603127] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:27.735121] LOG: [CONN] Frame received (11 bytes): 0c fb 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:11:27.735242] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:11:27.735277] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:11:27.735292] LOG: [CONN] Battery updated: 4091mV (91%) -[2026-02-20T18:11:27.793427] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:27.793559] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:27.793580] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:29.996730] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:11:29.996894] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:11:29.996906] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:11:30.698981] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:11:30.699086] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:11:30.699105] LOG: [API] Response (200) in 0.70s: {"success":true,"expires_at":1771640190} -[2026-02-20T18:11:30.699129] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:11:30.699147] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:11:30.700267] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:11:30.700298] LOG: [APP] Upload success: +1 items (total: 46) -[2026-02-20T18:11:31.797432] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.14562, accuracy=3.8m -[2026-02-20T18:11:32.602869] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:32.654063] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:32.654204] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:32.654225] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:34.186087] LOG: [CONN] Frame received (30 bytes): 88 2f c3 05 05 61 fa c7 7e cc 02 9c 75 91 bb d8 93 f5 cd f5 e2 8f 8e d2 4f 83 b6 07 f9 2b -[2026-02-20T18:11:34.186237] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:11:34.186301] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:11:34.186343] LOG: [RX PARSE] RAW Packet (27 bytes): 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B -[2026-02-20T18:11:34.186356] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T18:11:34.186367] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:11:34.186394] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=5, firstHop=0x61, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=20 bytes -[2026-02-20T18:11:34.186407] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=5 -[2026-02-20T18:11:34.186421] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:11:34.186433] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:11:34.186574] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:11:34.186588] LOG: [RX FILTER] Raw packet (27 bytes): 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B -[2026-02-20T18:11:34.186606] LOG: [RX FILTER] Header: 0x05 | PathLength: 5 | SNR: 11.75 -[2026-02-20T18:11:34.186621] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:11:34.186633] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) -[2026-02-20T18:11:34.186683] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:11:34.186694] LOG: [RX LOG] Dropped packet hex: 05 05 61 FA C7 7E CC 02 9C 75 91 BB D8 93 F5 CD F5 E2 8F 8E D2 4F 83 B6 07 F9 2B -[2026-02-20T18:11:35.700688] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:11:36.788827] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14439, accuracy=3.8m -[2026-02-20T18:11:37.573651] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:11:37.573736] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:11:37.602615] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:37.690899] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:37.690954] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:37.690962] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:41.761891] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14320, accuracy=3.8m -[2026-02-20T18:11:42.605468] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:42.705516] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:42.705636] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:42.705663] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:47.095614] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14189, accuracy=3.8m -[2026-02-20T18:11:47.603220] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:47.743499] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2f 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:47.743636] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:47.743652] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:51.792426] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.14094, accuracy=3.8m -[2026-02-20T18:11:51.792474] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:11:51.792547] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:11:52.575321] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:11:52.575463] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:11:52.602873] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:52.753094] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 2f 0c 00 00 00 8a 23 00 00 -[2026-02-20T18:11:52.753231] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:52.753252] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:11:54.996573] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:11:54.996656] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:11:54.996667] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:11:54.996688] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:11:54.996710] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35796, -122.14094 [0.3w]" -[2026-02-20T18:11:54.996716] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:11:54.996720] LOG: [TX LOG] Payload: "@[MapperBot] 47.35796, -122.14094 [0.3w]" -[2026-02-20T18:11:54.996725] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:11:54.996730] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:11:54.996736] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:11:54.996741] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:11:54.996749] LOG: [CONN] Sending ping: @[MapperBot] 47.35796, -122.14094 [0.3w] -[2026-02-20T18:11:55.066169] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:11:55.066293] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:11:55.066312] LOG: [CONN] Received OK response -[2026-02-20T18:11:56.550183] LOG: [CONN] Frame received (73 bytes): 88 31 c3 15 01 cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:11:56.550232] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:11:56.550266] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:11:56.550309] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:11:56.550320] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:11:56.550330] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:11:56.550348] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=67 bytes -[2026-02-20T18:11:56.550360] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:11:56.550369] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:11:56.550376] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 -[2026-02-20T18:11:56.550386] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:11:56.550394] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:11:56.550488] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:11:56.550495] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:11:56.550502] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:11:56.756571] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.14027, accuracy=3.8m -[2026-02-20T18:11:57.603629] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:11:57.603863] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:11:57.795884] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:11:57.796029] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:11:57.796048] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:11:57.796070] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:11:57.852784] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0d 00 00 00 8a 23 00 00 -[2026-02-20T18:11:57.852870] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:11:57.852879] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:11:58.069424] LOG: [PING] Ping sent successfully -[2026-02-20T18:12:00.000435] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:12:01.767319] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.13949, accuracy=3.8m -[2026-02-20T18:12:02.605217] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:02.714198] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0d 00 00 00 8a 23 00 00 -[2026-02-20T18:12:02.714284] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:02.714296] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:12:03.071116] LOG: [PING] RX listening window ended -[2026-02-20T18:12:03.071274] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:12:03.071303] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:12:03.071386] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:12:03.071404] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:12:03.071417] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:12:03.071443] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:12:03.071465] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:12:03.071873] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:12:06.760376] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13861, accuracy=3.8m -[2026-02-20T18:12:07.573824] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:12:07.574050] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:12:07.574076] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:12:07.602804] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:07.752914] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c3 31 0d 00 00 00 8a 23 00 00 -[2026-02-20T18:12:07.753029] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:07.753055] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:12:08.049957] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:12:08.050035] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:12:08.050058] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640227} -[2026-02-20T18:12:08.050078] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:12:08.050103] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:12:08.050485] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:12:08.050510] LOG: [APP] Upload success: +1 items (total: 47) -[2026-02-20T18:12:08.076209] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:12:08.076275] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:12:09.196952] LOG: [CONN] Frame received (83 bytes): 88 31 c0 15 0c cc 1b 9d 50 7e 75 20 20 53 1f 9d cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d -[2026-02-20T18:12:09.197100] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:12:09.197144] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:12:09.197222] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:12:09.197245] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:12:09.197265] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:12:09.197301] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-64, payload=66 bytes -[2026-02-20T18:12:09.197315] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:12:09.197331] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:12:09.197342] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:12:09.197354] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 1B -[2026-02-20T18:12:09.197425] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:12:09.197442] LOG: [RX FILTER] Raw packet (80 bytes): 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:12:09.197465] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.25 -[2026-02-20T18:12:09.197475] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:12:09.197486] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:12:09.197501] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:12:09.197515] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:12:09.197527] LOG: [RX FILTER] Encrypted message: 63 bytes -[2026-02-20T18:12:09.197543] LOG: [CRYPTO] Decrypting message (63 bytes) -[2026-02-20T18:12:09.197718] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:09.197770] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:09.198006] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:12:09.198134] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:12:09.198146] LOG: [RX LOG] Dropped packet hex: 15 0C CC 1B 9D 50 7E 75 20 20 53 1F 9D CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:12:11.770700] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.13761, accuracy=3.8m -[2026-02-20T18:12:12.602627] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:12.703388] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c0 31 0d 00 00 00 8a 23 00 00 -[2026-02-20T18:12:12.703530] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:12.703563] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:12:13.051974] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:12:16.768124] LOG: [GPS SERVICE] Position stream fired: lat=47.35793, lon=-122.13646, accuracy=3.8m -[2026-02-20T18:12:17.603008] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:17.714705] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c0 31 0d 00 00 00 8a 23 00 00 -[2026-02-20T18:12:17.714841] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:17.714861] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:19.393358] LOG: [CONN] Frame received (90 bytes): 88 2f c2 15 15 cc 1b 9d 50 7e 75 20 20 20 53 d1 7a b8 1f fb 47 b0 a5 c7 db cc 81 9c dc 59 35 93 cf b8 80 a5 1b c5 61 4c 53 d5 ab 1f 36 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 52 62 52 6b 46 0c b4 24 df 31 fc 82 07 cc da fe 19 55 94 25 e0 39 e7 92 a9 03 64 ee e6 -[2026-02-20T18:12:19.393516] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:12:19.393552] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:12:19.393637] LOG: [RX PARSE] RAW Packet (87 bytes): 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 -[2026-02-20T18:12:19.393660] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:12:19.393672] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:12:19.393699] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=64 bytes -[2026-02-20T18:12:19.393713] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:12:19.393723] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:12:19.393738] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:12:19.393752] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 1B -[2026-02-20T18:12:19.393828] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:12:19.393845] LOG: [RX FILTER] Raw packet (87 bytes): 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 -[2026-02-20T18:12:19.393866] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 11.75 -[2026-02-20T18:12:19.393880] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:12:19.393892] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:12:19.393902] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:12:19.393920] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:12:19.393936] LOG: [RX FILTER] Encrypted message: 61 bytes -[2026-02-20T18:12:19.393947] LOG: [CRYPTO] Decrypting message (61 bytes) -[2026-02-20T18:12:19.394137] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:19.394187] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:19.394424] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:12:19.394963] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:12:19.395005] LOG: [RX LOG] Dropped packet hex: 15 15 CC 1B 9D 50 7E 75 20 20 20 53 D1 7A B8 1F FB 47 B0 A5 C7 DB CC 81 9C DC 59 35 93 CF B8 80 A5 1B C5 61 4C 53 D5 AB 1F 36 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 52 62 52 6B 46 0C B4 24 DF 31 FC 82 07 CC DA FE 19 55 94 25 E0 39 E7 92 A9 03 64 EE E6 -[2026-02-20T18:12:21.778272] LOG: [GPS SERVICE] Position stream fired: lat=47.35795, lon=-122.13539, accuracy=3.8m -[2026-02-20T18:12:22.573688] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:12:22.573794] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:12:22.603244] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:22.755404] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:22.755530] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:22.755548] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:26.768010] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13431, accuracy=3.8m -[2026-02-20T18:12:26.768055] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:12:26.768119] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:12:27.603813] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:12:27.603958] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:27.766081] LOG: [CONN] Frame received (11 bytes): 0c f7 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:12:27.766219] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:12:27.766237] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:12:27.766253] LOG: [CONN] Battery updated: 4087mV (91%) -[2026-02-20T18:12:27.822782] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:27.822857] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:27.822869] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:31.777690] LOG: [GPS SERVICE] Position stream fired: lat=47.35794, lon=-122.13318, accuracy=3.8m -[2026-02-20T18:12:32.602814] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:32.684724] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c2 2f 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:32.684855] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:32.684875] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:12:33.073140] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:12:33.073299] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:12:33.073318] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:12:33.073360] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:12:33.073408] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35794, -122.13318 [0.3w]" -[2026-02-20T18:12:33.073421] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:12:33.073435] LOG: [TX LOG] Payload: "@[MapperBot] 47.35794, -122.13318 [0.3w]" -[2026-02-20T18:12:33.073449] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:12:33.073461] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:12:33.073479] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:12:33.073489] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:12:33.073516] LOG: [CONN] Sending ping: @[MapperBot] 47.35794, -122.13318 [0.3w] -[2026-02-20T18:12:33.193003] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:12:33.193137] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:12:33.193150] LOG: [CONN] Received OK response -[2026-02-20T18:12:34.798984] LOG: [CONN] Frame received (73 bytes): 88 32 c2 15 01 cc 81 4e b1 9e c0 60 a7 8f 70 2e ac 9b 9e 75 97 18 0e 23 3d 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 1f 05 62 ca bf 9e d9 c1 b8 a5 4d ac c1 a3 2d b7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:12:34.799086] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:12:34.799109] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:12:34.799153] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 4E B1 9E C0 60 A7 8F 70 2E AC 9B 9E 75 97 18 0E 23 3D 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 1F 05 62 CA BF 9E D9 C1 B8 A5 4D AC C1 A3 2D B7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:12:34.799163] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:12:34.799173] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:12:34.799192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-62, payload=67 bytes -[2026-02-20T18:12:34.799204] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:12:34.799209] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:12:34.799216] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-62 -[2026-02-20T18:12:34.799225] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:12:34.799231] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:12:34.799244] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:12:34.799257] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:12:34.799263] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:12:36.193752] LOG: [PING] Ping sent successfully -[2026-02-20T18:12:36.793723] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.13200, accuracy=3.8m -[2026-02-20T18:12:37.574838] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:12:37.574974] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:12:37.602963] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:37.696033] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c2 32 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:37.696168] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:37.696189] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:12:38.075243] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:12:41.196177] LOG: [PING] RX listening window ended -[2026-02-20T18:12:41.196344] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:12:41.196378] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:12:41.196480] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:12:41.196494] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:12:41.196506] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:12:41.196536] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:12:41.196551] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:12:41.197003] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:12:41.771269] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.13087, accuracy=3.8m -[2026-02-20T18:12:42.603234] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:42.706777] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:42.706818] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:42.706823] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:46.203767] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:12:46.204043] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:12:46.204056] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:12:46.760529] LOG: [GPS SERVICE] Position stream fired: lat=47.35796, lon=-122.12985, accuracy=3.8m -[2026-02-20T18:12:46.831932] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:12:46.831963] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:12:46.831968] LOG: [API] Response (200) in 0.63s: {"success":true,"expires_at":1771640266} -[2026-02-20T18:12:46.831974] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:12:46.831980] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:12:46.832183] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:12:46.832189] LOG: [APP] Upload success: +1 items (total: 48) -[2026-02-20T18:12:47.603794] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:47.714345] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0d 00 00 00 8b 23 00 00 -[2026-02-20T18:12:47.714394] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:47.714400] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:48.717797] LOG: [CONN] Frame received (162 bytes): 88 2d ba 15 0b af d1 86 67 38 75 20 20 75 7e cc 11 93 3c 07 9e 13 18 5e f4 ec 28 a0 53 de f2 a2 2d 8a 78 94 00 55 c7 e6 bd 6c cb 71 6b 8f fc 48 91 32 f0 1a 63 e8 9e 24 9d b8 ad 04 d6 37 e5 13 bf 33 d1 6d df d1 8c 6a b8 dd 94 a9 3e f6 b6 15 8e e8 00 29 3e e9 5c 32 24 a3 ec cd 61 b3 a6 e9 71 18 88 6d 22 67 5d 51 49 36 8e 24 0f 18 c2 58 b4 5b 59 6d 2f f8 1d 8d 5d 05 0b 6f 79 f7 10 f2 b7 a5 bc 86 22 e4 21 83 67 fd 42 a1 d4 54 51 c4 b7 26 d3 b0 48 81 16 4b ad 6b 27 a1 7f 0f 1f 45 38 d1 -[2026-02-20T18:12:48.717876] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:12:48.717893] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:12:48.717942] LOG: [RX PARSE] RAW Packet (159 bytes): 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 -[2026-02-20T18:12:48.717952] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:12:48.717960] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:12:48.717978] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0xaf, lastHop=0xcc, SNR=11.25, RSSI=-70, payload=146 bytes -[2026-02-20T18:12:48.717986] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:12:48.717992] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:12:48.717996] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:12:48.718043] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:12:48.718050] LOG: [RX FILTER] Raw packet (159 bytes): 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 -[2026-02-20T18:12:48.718063] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 11.25 -[2026-02-20T18:12:48.718070] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) -[2026-02-20T18:12:48.718075] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:12:48.718083] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:12:48.718088] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:12:48.718092] LOG: [RX FILTER] Encrypted message: 143 bytes -[2026-02-20T18:12:48.718100] LOG: [CRYPTO] Decrypting message (143 bytes) -[2026-02-20T18:12:48.718232] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:48.718258] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:12:48.718371] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:12:48.718439] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:12:48.718443] LOG: [RX LOG] Dropped packet hex: 15 0B AF D1 86 67 38 75 20 20 75 7E CC 11 93 3C 07 9E 13 18 5E F4 EC 28 A0 53 DE F2 A2 2D 8A 78 94 00 55 C7 E6 BD 6C CB 71 6B 8F FC 48 91 32 F0 1A 63 E8 9E 24 9D B8 AD 04 D6 37 E5 13 BF 33 D1 6D DF D1 8C 6A B8 DD 94 A9 3E F6 B6 15 8E E8 00 29 3E E9 5C 32 24 A3 EC CD 61 B3 A6 E9 71 18 88 6D 22 67 5D 51 49 36 8E 24 0F 18 C2 58 B4 5B 59 6D 2F F8 1D 8D 5D 05 0B 6F 79 F7 10 F2 B7 A5 BC 86 22 E4 21 83 67 FD 42 A1 D4 54 51 C4 B7 26 D3 B0 48 81 16 4B AD 6B 27 A1 7F 0F 1F 45 38 D1 -[2026-02-20T18:12:51.784824] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12911, accuracy=3.8m -[2026-02-20T18:12:51.834821] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:12:52.573739] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:12:52.573807] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:12:52.604391] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:52.720963] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:12:52.721012] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:52.721017] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:12:56.761962] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.12850, accuracy=3.8m -[2026-02-20T18:12:57.602829] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:12:57.603010] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:12:57.675862] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:12:57.676001] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:12:57.676021] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:12:57.676038] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T18:12:57.733255] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:12:57.733354] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:12:57.733378] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:01.793809] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.12814, accuracy=3.8m -[2026-02-20T18:13:01.793851] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:13:01.793911] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:13:02.602847] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:02.743796] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:02.743901] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:02.743920] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:06.795902] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12786, accuracy=3.9m -[2026-02-20T18:13:07.574041] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:13:07.574211] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:13:07.602896] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:07.754357] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ba 2d 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:07.754501] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:07.754555] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:11.198947] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:13:11.199105] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:13:11.199124] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:13:11.199173] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:13:11.199216] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35798, -122.12786 [0.3w]" -[2026-02-20T18:13:11.199244] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:13:11.199254] LOG: [TX LOG] Payload: "@[MapperBot] 47.35798, -122.12786 [0.3w]" -[2026-02-20T18:13:11.199268] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:13:11.199287] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:13:11.199299] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:13:11.199309] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:13:11.199336] LOG: [CONN] Sending ping: @[MapperBot] 47.35798, -122.12786 [0.3w] -[2026-02-20T18:13:11.262669] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:13:11.262764] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:13:11.262774] LOG: [CONN] Received OK response -[2026-02-20T18:13:11.805077] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12750, accuracy=16.8m -[2026-02-20T18:13:12.104758] LOG: [CONN] Frame received (73 bytes): 88 2e c3 15 01 cc 81 21 0d 9e 34 1f c0 6e 0a 3e 49 67 38 c0 49 0a c1 f7 79 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 00 f6 49 89 85 63 fd b3 ac 89 7c 21 30 a2 52 41 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:13:12.104811] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:12.104820] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:12.104836] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 21 0D 9E 34 1F C0 6E 0A 3E 49 67 38 C0 49 0A C1 F7 79 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 00 F6 49 89 85 63 FD B3 AC 89 7C 21 30 A2 52 41 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:13:12.104840] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:12.104843] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:13:12.104852] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=67 bytes -[2026-02-20T18:13:12.104856] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:13:12.104858] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:13:12.104862] LOG: [TX LOG] Processing rx_log entry: SNR=11.5, RSSI=-61 -[2026-02-20T18:13:12.104864] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:13:12.104866] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:13:12.104871] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:12.104873] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:12.104875] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:13:12.604031] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:12.765278] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c3 2e 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:12.765426] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:12.765446] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:13:14.269875] LOG: [PING] Ping sent successfully -[2026-02-20T18:13:16.200374] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:13:16.793558] LOG: [GPS SERVICE] Position stream fired: lat=47.35797, lon=-122.12704, accuracy=3.8m -[2026-02-20T18:13:17.602937] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:17.774182] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:17.774283] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:17.774299] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:19.271566] LOG: [PING] RX listening window ended -[2026-02-20T18:13:19.271715] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:13:19.271749] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:13:19.271825] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:13:19.271837] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:13:19.271850] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:13:19.271879] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:13:19.271893] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:13:19.272322] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:13:21.792192] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12682, accuracy=3.9m -[2026-02-20T18:13:22.573623] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:13:22.573730] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:13:22.573736] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:13:22.602743] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:22.752952] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:22.753108] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:22.753133] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:23.043616] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:13:23.043711] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:13:23.043732] LOG: [API] Response (200) in 0.47s: {"success":true,"expires_at":1771640302} -[2026-02-20T18:13:23.043752] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:13:23.043787] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:13:23.044491] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:13:23.044519] LOG: [APP] Upload success: +1 items (total: 49) -[2026-02-20T18:13:24.273649] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:13:24.273805] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:13:27.602779] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:13:27.602903] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:27.761241] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:13:27.761313] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:13:27.761318] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:13:27.761323] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:13:27.823455] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:27.823598] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:27.823625] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:28.048369] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:13:30.060884] LOG: [CONN] Frame received (45 bytes): 88 2f cc 15 05 af d1 86 9d cc 72 9c 2e 66 1b 2d 35 15 e3 2f 3f 26 d2 28 6c a7 c8 dc f3 a9 3c 66 1b 39 b2 6d cd 15 79 ad b1 13 3d 84 6b -[2026-02-20T18:13:30.061018] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:30.061046] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:30.061086] LOG: [RX PARSE] RAW Packet (42 bytes): 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B -[2026-02-20T18:13:30.061104] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:30.061113] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:13:30.061143] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=5, firstHop=0xaf, lastHop=0xcc, SNR=11.75, RSSI=-52, payload=35 bytes -[2026-02-20T18:13:30.061154] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=5 -[2026-02-20T18:13:30.061166] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:30.061176] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:30.061210] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:13:30.061219] LOG: [RX FILTER] Raw packet (42 bytes): 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B -[2026-02-20T18:13:30.061242] LOG: [RX FILTER] Header: 0x15 | PathLength: 5 | SNR: 11.75 -[2026-02-20T18:13:30.061253] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:13:30.061266] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:13:30.061275] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:13:30.061283] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:13:30.061329] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:13:30.061337] LOG: [RX LOG] Dropped packet hex: 15 05 AF D1 86 9D CC 72 9C 2E 66 1B 2D 35 15 E3 2F 3F 26 D2 28 6C A7 C8 DC F3 A9 3C 66 1B 39 B2 6D CD 15 79 AD B1 13 3D 84 6B -[2026-02-20T18:13:31.787588] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.12665, accuracy=4.6m -[2026-02-20T18:13:32.602640] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:32.651868] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 2f 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:32.651921] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:32.651926] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:35.661485] LOG: [CONN] Frame received (47 bytes): 88 31 cc 15 07 43 37 6c 3e 32 db cc 72 d4 4a 40 aa 36 f7 e3 bd 9b d1 71 dd c4 0c d0 9e 91 9e 0c ef 46 6e 7f 60 c4 47 42 bf 92 5b 10 03 53 ab -[2026-02-20T18:13:35.661690] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:35.661735] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:35.661794] LOG: [RX PARSE] RAW Packet (44 bytes): 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB -[2026-02-20T18:13:35.661815] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:35.661823] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:13:35.661947] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0x43, lastHop=0xcc, SNR=12.25, RSSI=-52, payload=35 bytes -[2026-02-20T18:13:35.661960] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:13:35.661967] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:35.661983] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:35.662025] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:13:35.662036] LOG: [RX FILTER] Raw packet (44 bytes): 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB -[2026-02-20T18:13:35.662063] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 12.25 -[2026-02-20T18:13:35.662081] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:13:35.662097] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:13:35.662110] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:13:35.662120] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:13:35.662190] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:13:35.662199] LOG: [RX LOG] Dropped packet hex: 15 07 43 37 6C 3E 32 DB CC 72 D4 4A 40 AA 36 F7 E3 BD 9B D1 71 DD C4 0C D0 9E 91 9E 0C EF 46 6E 7F 60 C4 47 42 BF 92 5B 10 03 53 AB -[2026-02-20T18:13:37.573724] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:13:37.573818] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:13:37.605876] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:37.663444] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:37.663532] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:37.663547] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:42.602991] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:42.676365] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 31 0d 00 00 00 8c 23 00 00 -[2026-02-20T18:13:42.676494] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:42.676514] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:43.084240] LOG: [CONN] Frame received (130 bytes): 88 30 cc 15 0a 1f 7d c7 7e 7a 29 dc 8b 9d cc 72 17 7c 1e ee 7d cb cd b4 32 fa 4f 9d 75 a0 a4 8b 44 e0 69 91 b2 5c 6f a9 6a 90 0d e5 e7 5b b2 9c a0 51 3a 37 c6 0f 8a 9b 05 cf 06 65 a4 c1 6b c6 e4 23 55 2b 5a 3a f4 f2 a7 99 86 56 15 b9 e8 cc 60 13 aa bb b9 b5 36 3e 30 6a 56 2c 09 08 9e 79 f6 2e 66 f6 7f a9 8b e1 d8 99 93 1b 22 f2 14 08 9e c3 34 98 1c b2 66 a6 57 06 08 08 a2 d2 bd af 0e 1d -[2026-02-20T18:13:43.084401] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:43.084431] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:43.084541] LOG: [RX PARSE] RAW Packet (127 bytes): 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D -[2026-02-20T18:13:43.084567] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:43.084578] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:13:43.084613] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x1f, lastHop=0xcc, SNR=12.0, RSSI=-52, payload=115 bytes -[2026-02-20T18:13:43.084627] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:13:43.084642] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:43.084654] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:43.084756] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:13:43.084768] LOG: [RX FILTER] Raw packet (127 bytes): 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D -[2026-02-20T18:13:43.084794] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.0 -[2026-02-20T18:13:43.084813] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:13:43.084824] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:13:43.084834] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:13:43.084849] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:13:43.084971] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:13:43.084987] LOG: [RX LOG] Dropped packet hex: 15 0A 1F 7D C7 7E 7A 29 DC 8B 9D CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF 0E 1D -[2026-02-20T18:13:44.520026] LOG: [CONN] Frame received (129 bytes): 88 32 ce 15 0b 1f 7d c7 7e 75 20 20 20 75 7e cc 72 17 7c 1e ee 7d cb cd b4 32 fa 4f 9d 75 a0 a4 8b 44 e0 69 91 b2 5c 6f a9 6a 90 0d e5 e7 5b b2 9c a0 51 3a 37 c6 0f 8a 9b 05 cf 06 65 a4 c1 6b c6 e4 23 55 2b 5a 3a f4 f2 a7 99 86 56 15 b9 e8 cc 60 13 aa bb b9 b5 36 3e 30 6a 56 2c 09 08 9e 79 f6 2e 66 f6 7f a9 8b e1 d8 99 93 1b 22 f2 14 08 9e c3 34 98 1c b2 66 a6 57 06 08 08 a2 d2 bd af -[2026-02-20T18:13:44.520182] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:44.520217] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:44.520326] LOG: [RX PARSE] RAW Packet (126 bytes): 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF -[2026-02-20T18:13:44.520350] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:44.520361] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:13:44.520395] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=11, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-50, payload=113 bytes -[2026-02-20T18:13:44.520410] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=11 -[2026-02-20T18:13:44.520420] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:44.520434] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:44.520534] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:13:44.520545] LOG: [RX FILTER] Raw packet (126 bytes): 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF -[2026-02-20T18:13:44.520570] LOG: [RX FILTER] Header: 0x15 | PathLength: 11 | SNR: 12.5 -[2026-02-20T18:13:44.520584] LOG: [RX FILTER] ✓ RSSI OK (-50 < -30) -[2026-02-20T18:13:44.520599] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:13:44.520610] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:13:44.520620] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:13:44.520887] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:13:44.520919] LOG: [RX LOG] Dropped packet hex: 15 0B 1F 7D C7 7E 75 20 20 20 75 7E CC 72 17 7C 1E EE 7D CB CD B4 32 FA 4F 9D 75 A0 A4 8B 44 E0 69 91 B2 5C 6F A9 6A 90 0D E5 E7 5B B2 9C A0 51 3A 37 C6 0F 8A 9B 05 CF 06 65 A4 C1 6B C6 E4 23 55 2B 5A 3A F4 F2 A7 99 86 56 15 B9 E8 CC 60 13 AA BB B9 B5 36 3E 30 6A 56 2C 09 08 9E 79 F6 2E 66 F6 7F A9 8B E1 D8 99 93 1B 22 F2 14 08 9E C3 34 98 1C B2 66 A6 57 06 08 08 A2 D2 BD AF -[2026-02-20T18:13:47.602908] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:47.712962] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 32 0d 00 00 00 8d 23 00 00 -[2026-02-20T18:13:47.713098] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:47.713118] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:49.273898] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:13:49.274038] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:13:49.274065] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:13:49.274107] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:13:49.274152] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35798, -122.12665 [0.3w]" -[2026-02-20T18:13:49.274165] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:13:49.274188] LOG: [TX LOG] Payload: "@[MapperBot] 47.35798, -122.12665 [0.3w]" -[2026-02-20T18:13:49.274201] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:13:49.274214] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:13:49.274230] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:13:49.274242] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:13:49.274264] LOG: [CONN] Sending ping: @[MapperBot] 47.35798, -122.12665 [0.3w] -[2026-02-20T18:13:49.425342] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:13:49.425486] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:13:49.425499] LOG: [CONN] Received OK response -[2026-02-20T18:13:50.280780] LOG: [CONN] Frame received (73 bytes): 88 31 cb 15 01 cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:13:50.280900] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:50.280921] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:50.280975] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:13:50.280990] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:50.281] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:13:50.281057] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-53, payload=67 bytes -[2026-02-20T18:13:50.281072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:13:50.281080] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:13:50.281088] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-53 -[2026-02-20T18:13:50.281101] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:13:50.281108] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:13:50.281120] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:50.281128] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:50.281135] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:13:52.425048] LOG: [PING] Ping sent successfully -[2026-02-20T18:13:52.573715] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:13:52.573857] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:13:52.602726] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:52.754226] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0e 00 00 00 8d 23 00 00 -[2026-02-20T18:13:52.754358] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:52.754382] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:54.276406] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:13:57.425812] LOG: [PING] RX listening window ended -[2026-02-20T18:13:57.425886] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:13:57.425917] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:13:57.425978] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:13:57.425988] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:13:57.426005] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:13:57.426027] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:13:57.426045] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:13:57.442659] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:13:57.604486] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:13:57.604651] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:13:57.762287] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:13:57.762367] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:13:57.762375] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:13:57.762385] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:13:57.823312] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 31 0e 00 00 00 8d 23 00 00 -[2026-02-20T18:13:57.823468] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:13:57.823487] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:13:59.869456] LOG: [CONN] Frame received (84 bytes): 88 30 cb 15 0d cc db c7 7e 75 20 20 75 38 24 7a 9d cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d -[2026-02-20T18:13:59.869609] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:13:59.869638] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:13:59.869716] LOG: [RX PARSE] RAW Packet (81 bytes): 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:13:59.869747] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:13:59.869758] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:13:59.869785] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-53, payload=66 bytes -[2026-02-20T18:13:59.869798] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:13:59.869813] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:13:59.869825] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:13:59.869837] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:13:59.869907] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:13:59.869923] LOG: [RX FILTER] Raw packet (81 bytes): 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:13:59.869941] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.0 -[2026-02-20T18:13:59.869956] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:13:59.869967] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:13:59.869977] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:13:59.869994] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:13:59.870007] LOG: [RX FILTER] Encrypted message: 63 bytes -[2026-02-20T18:13:59.870018] LOG: [CRYPTO] Decrypting message (63 bytes) -[2026-02-20T18:13:59.870204] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:13:59.870257] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:13:59.870493] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:13:59.870695] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:13:59.870705] LOG: [RX LOG] Dropped packet hex: 15 0D CC DB C7 7E 75 20 20 75 38 24 7A 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:14:02.444276] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:14:02.444325] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:14:02.444331] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:14:02.603176] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:02.652828] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cb 30 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:02.652956] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:02.652975] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:02.927392] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:14:02.927441] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:14:02.927448] LOG: [API] Response (200) in 0.48s: {"success":true,"expires_at":1771640342} -[2026-02-20T18:14:02.927459] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:14:02.927514] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:14:02.927687] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:14:02.927696] LOG: [APP] Upload success: +1 items (total: 50) -[2026-02-20T18:14:05.147102] LOG: [CONN] Frame received (86 bytes): 88 32 cc 15 13 cc db c7 7e 75 20 20 20 20 20 20 75 c5 26 07 a5 47 9d cc 81 6d 55 4b 9b 30 6b 4b 91 6b 1c b0 00 2a f2 bc 81 be 70 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 6f 92 e1 5f d4 a1 3d 97 f8 95 3f df 7d cc 52 59 19 55 94 25 e0 39 e7 92 a9 03 64 -[2026-02-20T18:14:05.147232] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:05.147263] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:05.147322] LOG: [RX PARSE] RAW Packet (83 bytes): 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 -[2026-02-20T18:14:05.147336] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:14:05.147349] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:14:05.147368] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-52, payload=62 bytes -[2026-02-20T18:14:05.147383] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:14:05.147394] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:05.147401] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:05.147415] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:14:05.147476] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:14:05.147485] LOG: [RX FILTER] Raw packet (83 bytes): 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 -[2026-02-20T18:14:05.147505] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.5 -[2026-02-20T18:14:05.147513] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:14:05.147526] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:14:05.147537] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:14:05.147547] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:14:05.147561] LOG: [RX FILTER] Encrypted message: 59 bytes -[2026-02-20T18:14:05.147572] LOG: [CRYPTO] Decrypting message (59 bytes) -[2026-02-20T18:14:05.147719] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:14:05.147760] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:14:05.147936] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:14:05.148034] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:14:05.148044] LOG: [RX LOG] Dropped packet hex: 15 13 CC DB C7 7E 75 20 20 20 20 20 20 75 C5 26 07 A5 47 9D CC 81 6D 55 4B 9B 30 6B 4B 91 6B 1C B0 00 2A F2 BC 81 BE 70 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 6F 92 E1 5F D4 A1 3D 97 F8 95 3F DF 7D CC 52 59 19 55 94 25 E0 39 E7 92 A9 03 64 -[2026-02-20T18:14:07.573645] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:14:07.573700] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:14:07.602819] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:07.785878] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:07.786021] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:07.786043] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:07.928620] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:14:12.602930] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:12.645506] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:12.645627] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:12.645645] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:17.604415] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:17.713262] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:17.713337] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:17.713349] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:21.772109] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.12583, accuracy=5.1m -[2026-02-20T18:14:21.772151] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:14:21.772206] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:14:22.574129] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:14:22.574303] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:14:22.605031] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:22.757223] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff cc 32 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:22.757350] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:22.757376] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:14:26.804161] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.12495, accuracy=3.8m -[2026-02-20T18:14:27.426712] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:14:27.426839] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:14:27.426854] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:14:27.426886] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:14:27.426921] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35803, -122.12495 [0.3w]" -[2026-02-20T18:14:27.426929] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:14:27.426933] LOG: [TX LOG] Payload: "@[MapperBot] 47.35803, -122.12495 [0.3w]" -[2026-02-20T18:14:27.426946] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:14:27.426953] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:14:27.426959] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:14:27.426967] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:14:27.426981] LOG: [CONN] Sending ping: @[MapperBot] 47.35803, -122.12495 [0.3w] -[2026-02-20T18:14:27.603332] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:14:27.603551] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:27.616331] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:14:27.616420] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:14:27.616430] LOG: [CONN] Received OK response -[2026-02-20T18:14:27.675669] LOG: [CONN] Frame received (11 bytes): 0c c5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:14:27.675793] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:14:27.675811] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:14:27.675834] LOG: [CONN] Battery updated: 4037mV (86%) -[2026-02-20T18:14:27.733932] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 32 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:27.734028] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:27.734046] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:29.787163] LOG: [CONN] Frame received (73 bytes): 88 30 c4 15 01 cc 81 9a 98 50 2f af 06 51 3e e2 dd 2e 84 fa f4 41 d5 c4 92 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 8c 1b 1b 42 16 eb 90 0f 1c 73 ba ce 7c ea 0d 7f 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:14:29.787230] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:29.787243] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:29.787267] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 9A 98 50 2F AF 06 51 3E E2 DD 2E 84 FA F4 41 D5 C4 92 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 8C 1B 1B 42 16 EB 90 0F 1C 73 BA CE 7C EA 0D 7F 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:14:29.787273] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:14:29.787277] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:14:29.787286] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes -[2026-02-20T18:14:29.787290] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:14:29.787295] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:14:29.787299] LOG: [TX LOG] Processing rx_log entry: SNR=12.0, RSSI=-60 -[2026-02-20T18:14:29.787302] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:14:29.787306] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:14:29.787310] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:29.787313] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:29.787318] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:14:30.617449] LOG: [PING] Ping sent successfully -[2026-02-20T18:14:31.772574] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.12443, accuracy=3.9m -[2026-02-20T18:14:32.427750] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:14:32.602947] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:32.686166] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0e 00 00 00 8e 23 00 00 -[2026-02-20T18:14:32.686306] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:32.686326] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:35.618456] LOG: [PING] RX listening window ended -[2026-02-20T18:14:35.618680] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:14:35.618712] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:14:35.618780] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:14:35.618788] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:14:35.618801] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:14:35.618817] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:14:35.618828] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:14:35.619459] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:14:36.771619] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.12384, accuracy=4.2m -[2026-02-20T18:14:37.426856] LOG: [CONN] Frame received (85 bytes): 88 2e c3 15 10 0a 53 7e 67 75 20 20 20 20 75 a5 e8 32 34 9d cc 11 71 a8 8f b5 48 f9 c6 76 0b 84 55 56 8b fa 54 ae f4 d4 0e 96 ac 16 b3 63 f8 4e 5f 88 78 d3 6c c7 36 a6 a5 da 7c 78 25 b6 43 5e 6a 7e 96 8d 40 f9 64 5a a7 aa 03 44 cc 24 06 e9 e3 b1 1a cb 4b -[2026-02-20T18:14:37.427028] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:37.427062] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:37.427154] LOG: [RX PARSE] RAW Packet (82 bytes): 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B -[2026-02-20T18:14:37.427178] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:14:37.427189] LOG: [RX PARSE] Path length offset: 1, Path length: 16 -[2026-02-20T18:14:37.427227] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=16, firstHop=0x0a, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=64 bytes -[2026-02-20T18:14:37.427242] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=16 -[2026-02-20T18:14:37.427257] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:37.427270] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:37.427346] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:14:37.427357] LOG: [RX FILTER] Raw packet (82 bytes): 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B -[2026-02-20T18:14:37.427381] LOG: [RX FILTER] Header: 0x15 | PathLength: 16 | SNR: 11.5 -[2026-02-20T18:14:37.427395] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:14:37.427412] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:14:37.427424] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:14:37.427435] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:14:37.427453] LOG: [RX FILTER] Encrypted message: 61 bytes -[2026-02-20T18:14:37.427464] LOG: [CRYPTO] Decrypting message (61 bytes) -[2026-02-20T18:14:37.427673] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:14:37.427728] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:14:37.427968] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:14:37.428106] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:14:37.428118] LOG: [RX LOG] Dropped packet hex: 15 10 0A 53 7E 67 75 20 20 20 20 75 A5 E8 32 34 9D CC 11 71 A8 8F B5 48 F9 C6 76 0B 84 55 56 8B FA 54 AE F4 D4 0E 96 AC 16 B3 63 F8 4E 5F 88 78 D3 6C C7 36 A6 A5 DA 7C 78 25 B6 43 5E 6A 7E 96 8D 40 F9 64 5A A7 AA 03 44 CC 24 06 E9 E3 B1 1A CB 4B -[2026-02-20T18:14:37.574146] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:14:37.574381] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:14:37.574409] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:14:37.602666] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:37.786225] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:14:37.786318] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:37.786336] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:38.245522] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:14:38.245577] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:14:38.245587] LOG: [API] Response (200) in 0.67s: {"success":true,"expires_at":1771640378} -[2026-02-20T18:14:38.245601] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:14:38.245612] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:14:38.245895] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:14:38.245905] LOG: [APP] Upload success: +1 items (total: 51) -[2026-02-20T18:14:40.620551] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:14:40.620773] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:14:41.784171] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.12306, accuracy=4.6m -[2026-02-20T18:14:42.605819] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:42.794] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:14:42.794134] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:42.794159] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:43.246969] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:14:46.063776] LOG: [CONN] Frame received (131 bytes): 88 2f c3 11 05 0c 64 c7 db cc 17 54 0f 83 fd 5b 05 3c 3e 19 e8 56 da dc b4 6b d2 0a da 33 9f 37 74 22 3a 0e 0a a9 61 9a cb f9 f0 f1 5e 66 1e 11 22 1e 60 b6 fd e0 5b b9 29 13 45 ce a9 4d 45 7c 41 76 43 3a 6a b0 4f e0 f8 bb 33 02 00 dd 92 3b db 1e 1e a3 53 a5 1a a9 61 f0 ab b3 86 96 09 6f 6a 73 99 a4 13 00 98 ff d9 67 4c 93 58 0a 92 00 00 00 00 00 00 00 00 f0 9f 90 87 f0 9f 90 87 f0 9f 90 87 -[2026-02-20T18:14:46.063870] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:46.063892] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:46.063941] LOG: [RX PARSE] RAW Packet (128 bytes): 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 -[2026-02-20T18:14:46.063953] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:14:46.063958] LOG: [RX PARSE] Path length offset: 1, Path length: 5 -[2026-02-20T18:14:46.063978] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=5, firstHop=0x0c, lastHop=0xcc, SNR=11.75, RSSI=-61, payload=121 bytes -[2026-02-20T18:14:46.063986] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=5 -[2026-02-20T18:14:46.063990] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:46.064359] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:46.064409] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:14:46.064414] LOG: [RX FILTER] Raw packet (128 bytes): 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 -[2026-02-20T18:14:46.064445] LOG: [RX FILTER] Header: 0x11 | PathLength: 5 | SNR: 11.75 -[2026-02-20T18:14:46.064455] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:14:46.064461] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:14:46.064465] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:14:46.064475] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:14:46.064549] LOG: [RX FILTER] ADVERT name extracted: "🐇🐇🐇" (6 chars) -[2026-02-20T18:14:46.064557] LOG: [RX FILTER] ADVERT name printable ratio: 0.0% -[2026-02-20T18:14:46.064565] LOG: [RX FILTER] ❌ DROPPED: name not printable -[2026-02-20T18:14:46.064617] LOG: [RX LOG] ❌ Packet dropped: name not printable -[2026-02-20T18:14:46.064624] LOG: [RX LOG] Dropped packet hex: 11 05 0C 64 C7 DB CC 17 54 0F 83 FD 5B 05 3C 3E 19 E8 56 DA DC B4 6B D2 0A DA 33 9F 37 74 22 3A 0E 0A A9 61 9A CB F9 F0 F1 5E 66 1E 11 22 1E 60 B6 FD E0 5B B9 29 13 45 CE A9 4D 45 7C 41 76 43 3A 6A B0 4F E0 F8 BB 33 02 00 DD 92 3B DB 1E 1E A3 53 A5 1A A9 61 F0 AB B3 86 96 09 6F 6A 73 99 A4 13 00 98 FF D9 67 4C 93 58 0A 92 00 00 00 00 00 00 00 00 F0 9F 90 87 F0 9F 90 87 F0 9F 90 87 -[2026-02-20T18:14:46.064856] LOG: [CONN] Frame received (33 bytes): 80 17 54 0f 83 fd 5b 05 3c 3e 19 e8 56 da dc b4 6b d2 0a da 33 9f 37 74 22 3a 0e 0a a9 61 9a cb f9 -[2026-02-20T18:14:46.064865] LOG: [CONN] Response code: 0x80 (128) -[2026-02-20T18:14:46.064870] LOG: [CONN] Unhandled frame: code=128 (0x80) -[2026-02-20T18:14:46.427122] LOG: [CONN] Frame received (44 bytes): 88 2e c3 15 04 62 1f db cc 72 67 b2 b8 a0 85 a8 9e fa 04 00 f4 4e 06 ce f9 04 20 56 62 e4 1b cb 9e 4a 5b 80 4c c3 5e 4e 5c a2 70 25 -[2026-02-20T18:14:46.427180] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:46.427220] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:46.427267] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 -[2026-02-20T18:14:46.427288] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:14:46.427300] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:14:46.427323] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x62, lastHop=0xcc, SNR=11.5, RSSI=-61, payload=35 bytes -[2026-02-20T18:14:46.427341] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:14:46.427352] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:46.427360] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:46.427409] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:14:46.427420] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 -[2026-02-20T18:14:46.427436] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 -[2026-02-20T18:14:46.427456] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:14:46.427468] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:14:46.427478] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:14:46.427495] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:14:46.427673] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:14:46.427687] LOG: [RX LOG] Dropped packet hex: 15 04 62 1F DB CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 25 -[2026-02-20T18:14:46.765899] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.12219, accuracy=4.2m -[2026-02-20T18:14:47.602986] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:47.686427] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:14:47.686723] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:47.686754] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:52.104476] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.12130, accuracy=4.2m -[2026-02-20T18:14:52.104530] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:14:52.104587] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:14:52.574410] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:14:52.574690] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:14:52.603017] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:54.882822] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:14:54.882962] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:54.882982] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:56.797779] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.12048, accuracy=4.5m -[2026-02-20T18:14:57.603565] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:14:57.603796] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:14:57.795952] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:14:57.796090] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:14:57.796109] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:14:57.796125] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:14:57.854219] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 2e 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:14:57.854348] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:14:57.854372] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:14:59.461750] LOG: [CONN] Frame received (57 bytes): 88 30 c3 15 12 62 1f c5 75 20 20 75 e9 24 43 6f 9b f7 13 c7 34 9d cc 72 67 b2 b8 a0 85 a8 9e fa 04 00 f4 4e 06 ce f9 04 20 56 62 e4 1b cb 9e 4a 5b 80 4c c3 5e 4e 5c a2 70 -[2026-02-20T18:14:59.461905] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:14:59.461942] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:14:59.462003] LOG: [RX PARSE] RAW Packet (54 bytes): 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 -[2026-02-20T18:14:59.462025] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:14:59.462039] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:14:59.462080] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0x62, lastHop=0xcc, SNR=12.0, RSSI=-61, payload=34 bytes -[2026-02-20T18:14:59.462095] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T18:14:59.462111] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:14:59.462125] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:14:59.462189] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:14:59.462208] LOG: [RX FILTER] Raw packet (54 bytes): 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 -[2026-02-20T18:14:59.462225] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 12.0 -[2026-02-20T18:14:59.462245] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:14:59.462255] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:14:59.462266] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:14:59.462283] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:14:59.462353] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:14:59.462365] LOG: [RX LOG] Dropped packet hex: 15 12 62 1F C5 75 20 20 75 E9 24 43 6F 9B F7 13 C7 34 9D CC 72 67 B2 B8 A0 85 A8 9E FA 04 00 F4 4E 06 CE F9 04 20 56 62 E4 1B CB 9E 4A 5B 80 4C C3 5E 4E 5C A2 70 -[2026-02-20T18:15:01.788969] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.11987, accuracy=4.3m -[2026-02-20T18:15:02.604851] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:02.651491] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 30 0e 00 00 00 8f 23 00 00 -[2026-02-20T18:15:02.651562] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:02.651574] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:05.620640] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:15:05.620801] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:15:05.620820] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:15:05.620870] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:15:05.620915] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35804, -122.11987 [0.3w]" -[2026-02-20T18:15:05.620932] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:15:05.620942] LOG: [TX LOG] Payload: "@[MapperBot] 47.35804, -122.11987 [0.3w]" -[2026-02-20T18:15:05.620956] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:15:05.620974] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:15:05.620987] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:15:05.620998] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:15:05.621031] LOG: [CONN] Sending ping: @[MapperBot] 47.35804, -122.11987 [0.3w] -[2026-02-20T18:15:05.713110] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:15:05.713240] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:15:05.713254] LOG: [CONN] Received OK response -[2026-02-20T18:15:05.830990] LOG: [CONN] Frame received (55 bytes): 88 31 c3 15 15 1f 2c 43 fb 23 7e 75 20 20 20 20 20 20 20 20 20 75 d6 53 7e cc 72 29 0b 56 9c 67 93 da 5f 1e d2 a4 ec 5b bb cd 93 1f ce 10 11 3c a4 45 30 26 20 cd 2d -[2026-02-20T18:15:05.831050] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:05.831062] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:05.831075] LOG: [RX PARSE] RAW Packet (52 bytes): 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D -[2026-02-20T18:15:05.831078] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:05.831082] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:15:05.831093] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=29 bytes -[2026-02-20T18:15:05.831098] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:15:05.831100] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:15:05.831103] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 -[2026-02-20T18:15:05.831107] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:15:05.831110] LOG: [TX LOG] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:15:05.831113] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x72, expected=0x81 -[2026-02-20T18:15:05.831116] LOG: [TX LOG] Ignoring: channel hash mismatch -[2026-02-20T18:15:05.831118] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:05.831121] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:05.831134] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:05.831136] LOG: [RX FILTER] Raw packet (52 bytes): 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D -[2026-02-20T18:15:05.831140] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.25 -[2026-02-20T18:15:05.831143] LOG: [RX FILTER] ✓ RSSI OK (-61 < -30) -[2026-02-20T18:15:05.831147] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:05.831149] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:15:05.831152] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:15:05.831167] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:05.831170] LOG: [RX LOG] Dropped packet hex: 15 15 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 75 D6 53 7E CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 CD 2D -[2026-02-20T18:15:06.780798] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.11967, accuracy=4.2m -[2026-02-20T18:15:07.124532] LOG: [CONN] Frame received (73 bytes): 88 33 c4 15 01 cc 81 68 b6 f0 d7 80 fa 36 70 1b b9 5d 1b 97 67 c9 98 a3 b2 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 67 bb de df 1f 37 f9 f5 77 12 0f db 0e 5b 7d a0 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:15:07.124702] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:07.124733] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:07.124807] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 68 B6 F0 D7 80 FA 36 70 1B B9 5D 1B 97 67 C9 98 A3 B2 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 67 BB DE DF 1F 37 F9 F5 77 12 0F DB 0E 5B 7D A0 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:15:07.124828] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:07.124839] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:15:07.124876] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=67 bytes -[2026-02-20T18:15:07.124891] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:15:07.124901] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:15:07.124919] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-60 -[2026-02-20T18:15:07.124930] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:15:07.124945] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:15:07.124957] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:07.124967] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:07.124983] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:15:07.573691] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:15:07.573837] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:15:07.603060] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:07.782414] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c4 33 0e 00 00 00 90 23 00 00 -[2026-02-20T18:15:07.782631] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:07.782646] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:15:08.715004] LOG: [PING] Ping sent successfully -[2026-02-20T18:15:10.621990] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:15:11.795105] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.11944, accuracy=17.9m -[2026-02-20T18:15:12.602894] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:12.642128] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 90 23 00 00 -[2026-02-20T18:15:12.642196] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:12.642203] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:13.716550] LOG: [PING] RX listening window ended -[2026-02-20T18:15:13.716612] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:15:13.716626] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:15:13.716660] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:15:13.716663] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:15:13.716666] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:15:13.716672] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:15:13.716676] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:15:13.717045] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:15:15.731364] LOG: [CONN] Frame received (65 bytes): 88 31 c7 15 18 1f 2c 43 fb 23 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7e 6c 1b cc 72 29 0b 56 9c 67 93 da 5f 1e d2 a4 ec 5b bb cd 93 1f ce 10 11 3c a4 45 30 26 20 9e 4a 5b 80 4c c3 5e 4e dc -[2026-02-20T18:15:15.731411] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:15.731423] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:15.731448] LOG: [RX PARSE] RAW Packet (62 bytes): 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC -[2026-02-20T18:15:15.731453] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:15.731455] LOG: [RX PARSE] Path length offset: 1, Path length: 24 -[2026-02-20T18:15:15.731463] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=24, firstHop=0x1f, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=36 bytes -[2026-02-20T18:15:15.731466] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=24 -[2026-02-20T18:15:15.731469] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:15.731472] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:15.731485] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:15.731487] LOG: [RX FILTER] Raw packet (62 bytes): 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC -[2026-02-20T18:15:15.731491] LOG: [RX FILTER] Header: 0x15 | PathLength: 24 | SNR: 12.25 -[2026-02-20T18:15:15.731496] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:15:15.731498] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:15.731501] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:15:15.731504] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:15:15.731519] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:15.731521] LOG: [RX LOG] Dropped packet hex: 15 18 1F 2C 43 FB 23 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 53 7E 6C 1B CC 72 29 0B 56 9C 67 93 DA 5F 1E D2 A4 EC 5B BB CD 93 1F CE 10 11 3C A4 45 30 26 20 9E 4A 5B 80 4C C3 5E 4E DC -[2026-02-20T18:15:16.769588] LOG: [GPS SERVICE] Position stream fired: lat=47.35809, lon=-122.11879, accuracy=5.0m -[2026-02-20T18:15:17.606407] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:17.696544] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0e 00 00 00 90 23 00 00 -[2026-02-20T18:15:17.696627] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:17.696634] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:18.468560] LOG: [APP] App resumed from background -[2026-02-20T18:15:18.717634] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:15:18.717736] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:15:18.717742] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:15:19.207503] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:15:19.207545] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:15:19.207552] LOG: [API] Response (200) in 0.49s: {"success":true,"expires_at":1771640419} -[2026-02-20T18:15:19.207560] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:15:19.207571] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:15:19.207755] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:15:19.207768] LOG: [APP] Upload success: +1 items (total: 52) -[2026-02-20T18:15:21.107075] LOG: [CONN] Frame received (57 bytes): 88 31 c8 15 13 87 f7 7e 75 20 20 20 75 07 24 6f d1 c3 c3 7a 6c c7 db cc 72 20 a0 33 f5 7b 6d 51 50 a7 90 3d 7f 7a 5b 33 1a 77 29 3b 12 82 1d bd 7e 9c 7c 0b 4c c3 8f 89 a1 -[2026-02-20T18:15:21.107249] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:21.107279] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:21.107341] LOG: [RX PARSE] RAW Packet (54 bytes): 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 -[2026-02-20T18:15:21.107356] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:21.107373] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:15:21.107394] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=19, firstHop=0x87, lastHop=0xcc, SNR=12.25, RSSI=-56, payload=33 bytes -[2026-02-20T18:15:21.107412] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=19 -[2026-02-20T18:15:21.107423] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:21.107433] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:21.107488] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:21.107500] LOG: [RX FILTER] Raw packet (54 bytes): 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 -[2026-02-20T18:15:21.107529] LOG: [RX FILTER] Header: 0x15 | PathLength: 19 | SNR: 12.25 -[2026-02-20T18:15:21.107543] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:15:21.107553] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:21.107569] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:15:21.107580] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:15:21.107644] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:21.107660] LOG: [RX LOG] Dropped packet hex: 15 13 87 F7 7E 75 20 20 20 75 07 24 6F D1 C3 C3 7A 6C C7 DB CC 72 20 A0 33 F5 7B 6D 51 50 A7 90 3D 7F 7A 5B 33 1A 77 29 3B 12 82 1D BD 7E 9C 7C 0B 4C C3 8F 89 A1 -[2026-02-20T18:15:21.775978] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11792, accuracy=4.1m -[2026-02-20T18:15:22.574004] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:15:22.574251] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:15:22.604795] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:22.669827] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c8 31 0e 00 00 00 90 23 00 00 -[2026-02-20T18:15:22.669891] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:22.669900] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:15:24.210737] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:15:26.768115] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11699, accuracy=4.0m -[2026-02-20T18:15:26.768165] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:15:26.768235] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:15:27.602612] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:15:27.602732] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:27.671735] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:15:27.671793] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:15:27.671801] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:15:27.671808] LOG: [CONN] Battery updated: 4080mV (90%) -[2026-02-20T18:15:27.744170] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c8 31 0e 00 00 00 90 23 00 00 -[2026-02-20T18:15:27.744229] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:27.744233] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:29.293634] LOG: [CONN] Frame received (131 bytes): 88 30 c8 15 0c 1f 8b 18 7e 75 20 20 75 7e 6c db cc 72 6e 22 cd 32 b5 de 34 90 77 0b c6 de 2d 02 ac 62 2d 84 68 8a f4 88 a0 cc 0d d3 57 95 87 44 ef f8 05 e6 1a 5a 1e 7a 4a 30 a3 af 49 f7 68 36 ef 8e 90 04 cf 3a 5d 98 07 75 98 2b 4c 8c 73 b9 6f 80 e7 ef 16 90 d8 26 63 f5 98 5b b6 cc 93 b1 2f d1 fd ed 7f 37 a8 7c e1 41 aa 28 74 b4 e7 fb 81 75 08 00 60 ac 4f 5d 80 48 39 51 9f bc 3e fe fc 3d 32 -[2026-02-20T18:15:29.293747] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:29.293765] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:29.293806] LOG: [RX PARSE] RAW Packet (128 bytes): 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 -[2026-02-20T18:15:29.293815] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:29.293818] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:15:29.293832] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0x1f, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=114 bytes -[2026-02-20T18:15:29.293838] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:15:29.293841] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:29.293847] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:29.293881] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:29.293884] LOG: [RX FILTER] Raw packet (128 bytes): 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 -[2026-02-20T18:15:29.293893] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.0 -[2026-02-20T18:15:29.293900] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:15:29.293905] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:29.293908] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:15:29.293914] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:15:29.293955] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:29.293960] LOG: [RX LOG] Dropped packet hex: 15 0C 1F 8B 18 7E 75 20 20 75 7E 6C DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 4F 5D 80 48 39 51 9F BC 3E FE FC 3D 32 -[2026-02-20T18:15:31.786778] LOG: [GPS SERVICE] Position stream fired: lat=47.35811, lon=-122.11604, accuracy=4.0m -[2026-02-20T18:15:32.602726] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:32.652259] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 0e 00 00 00 91 23 00 00 -[2026-02-20T18:15:32.652329] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:32.652338] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:15:36.768826] LOG: [GPS SERVICE] Position stream fired: lat=47.35812, lon=-122.11547, accuracy=3.9m -[2026-02-20T18:15:37.573918] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:15:37.574104] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:15:37.603101] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:37.785884] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 0e 00 00 00 91 23 00 00 -[2026-02-20T18:15:37.785979] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:37.785992] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:15:40.576400] LOG: [CONN] Frame received (140 bytes): 88 32 c2 15 15 1f 8b 18 7e 7a 1e 5a ab 26 43 bf 56 fb e5 1b 5a cd 7a 7e db cc 72 6e 22 cd 32 b5 de 34 90 77 0b c6 de 2d 02 ac 62 2d 84 68 8a f4 88 a0 cc 0d d3 57 95 87 44 ef f8 05 e6 1a 5a 1e 7a 4a 30 a3 af 49 f7 68 36 ef 8e 90 04 cf 3a 5d 98 07 75 98 2b 4c 8c 73 b9 6f 80 e7 ef 16 90 d8 26 63 f5 98 5b b6 cc 93 b1 2f d1 fd ed 7f 37 a8 7c e1 41 aa 28 74 b4 e7 fb 81 75 08 00 60 ac 5d 80 48 39 51 9f bc 3e fe fc 3d 32 95 -[2026-02-20T18:15:40.576585] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:40.576624] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:40.576771] LOG: [RX PARSE] RAW Packet (137 bytes): 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 -[2026-02-20T18:15:40.576798] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:40.576809] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:15:40.576849] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x1f, lastHop=0xcc, SNR=12.5, RSSI=-62, payload=114 bytes -[2026-02-20T18:15:40.576863] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:15:40.576880] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:40.576892] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:40.577007] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:40.577026] LOG: [RX FILTER] Raw packet (137 bytes): 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 -[2026-02-20T18:15:40.577056] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 12.5 -[2026-02-20T18:15:40.577074] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:15:40.577086] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:40.577105] LOG: [RX FILTER] Channel hash: 0x72 -[2026-02-20T18:15:40.577117] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0x72 -[2026-02-20T18:15:40.577250] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:40.577262] LOG: [RX LOG] Dropped packet hex: 15 15 1F 8B 18 7E 7A 1E 5A AB 26 43 BF 56 FB E5 1B 5A CD 7A 7E DB CC 72 6E 22 CD 32 B5 DE 34 90 77 0B C6 DE 2D 02 AC 62 2D 84 68 8A F4 88 A0 CC 0D D3 57 95 87 44 EF F8 05 E6 1A 5A 1E 7A 4A 30 A3 AF 49 F7 68 36 EF 8E 90 04 CF 3A 5D 98 07 75 98 2B 4C 8C 73 B9 6F 80 E7 EF 16 90 D8 26 63 F5 98 5B B6 CC 93 B1 2F D1 FD ED 7F 37 A8 7C E1 41 AA 28 74 B4 E7 FB 81 75 08 00 60 AC 5D 80 48 39 51 9F BC 3E FE FC 3D 32 95 -[2026-02-20T18:15:41.765459] LOG: [GPS SERVICE] Position stream fired: lat=47.35810, lon=-122.11521, accuracy=3.8m -[2026-02-20T18:15:42.602803] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:42.731030] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 32 0e 00 00 00 91 23 00 00 -[2026-02-20T18:15:42.731081] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:42.731088] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:43.136053] LOG: [APP] App resumed from background -[2026-02-20T18:15:43.718416] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:15:43.718575] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:15:43.718581] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:15:43.718601] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:15:43.718619] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35810, -122.11521 [0.3w]" -[2026-02-20T18:15:43.718623] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:15:43.718624] LOG: [TX LOG] Payload: "@[MapperBot] 47.35810, -122.11521 [0.3w]" -[2026-02-20T18:15:43.718635] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:15:43.718638] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:15:43.718641] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:15:43.718644] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:15:43.718651] LOG: [CONN] Sending ping: @[MapperBot] 47.35810, -122.11521 [0.3w] -[2026-02-20T18:15:43.843172] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:15:43.843248] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:15:43.843254] LOG: [CONN] Received OK response -[2026-02-20T18:15:45.584109] LOG: [CONN] Frame received (73 bytes): 88 31 c3 15 01 cc 81 df b9 79 20 81 c6 3b 83 44 e3 a2 d9 d2 ab 35 7f 10 18 e7 f6 79 96 7b 7a 1a 83 f2 2c 4f 28 76 21 94 70 40 bb 57 c2 49 f0 6e 91 c8 3c 6e e1 68 d3 eb 6e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:15:45.584243] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:45.584267] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:45.584323] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 DF B9 79 20 81 C6 3B 83 44 E3 A2 D9 D2 AB 35 7F 10 18 E7 F6 79 96 7B 7A 1A 83 F2 2C 4F 28 76 21 94 70 40 BB 57 C2 49 F0 6E 91 C8 3C 6E E1 68 D3 EB 6E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:15:45.584387] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:45.584395] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:15:45.584418] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-61, payload=67 bytes -[2026-02-20T18:15:45.584429] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:15:45.584440] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:15:45.584452] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-61 -[2026-02-20T18:15:45.584460] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:15:45.584470] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:15:45.584480] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:45.584487] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:45.584500] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:15:46.787424] LOG: [GPS SERVICE] Position stream fired: lat=47.35813, lon=-122.11473, accuracy=16.5m -[2026-02-20T18:15:46.843717] LOG: [PING] Ping sent successfully -[2026-02-20T18:15:47.605022] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:47.743418] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0e 00 00 00 92 23 00 00 -[2026-02-20T18:15:47.743590] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:47.743637] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:48.720448] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:15:51.794664] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11386, accuracy=3.8m -[2026-02-20T18:15:51.844983] LOG: [PING] RX listening window ended -[2026-02-20T18:15:51.845153] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:15:51.845184] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:15:51.845260] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:15:51.845289] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:15:51.845304] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:15:51.845330] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:15:51.845351] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:15:51.857262] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:15:52.573736] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:15:52.573949] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:15:52.573966] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:15:52.602907] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:52.753383] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c3 31 0e 00 00 00 92 23 00 00 -[2026-02-20T18:15:52.753534] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:52.753556] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:52.813340] LOG: [CONN] Frame received (64 bytes): 88 2f c4 15 09 d4 5e ca 29 1f 7a db 1b cc ad f7 34 05 f8 da eb f3 50 8d de f4 ba 96 ed ef c8 7b 67 07 7f 94 f4 32 13 77 e3 ec 2e 2a ab 04 90 af c1 c5 a1 90 0f df 6a 0d 8f 63 e9 9c 6a 99 f5 f1 -[2026-02-20T18:15:52.813430] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:52.813450] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:52.813489] LOG: [RX PARSE] RAW Packet (61 bytes): 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 -[2026-02-20T18:15:52.813499] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:52.813508] LOG: [RX PARSE] Path length offset: 1, Path length: 9 -[2026-02-20T18:15:52.813527] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=9, firstHop=0xd4, lastHop=0xcc, SNR=11.75, RSSI=-60, payload=50 bytes -[2026-02-20T18:15:52.813544] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=9 -[2026-02-20T18:15:52.813550] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:52.813556] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:52.813591] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:52.813598] LOG: [RX FILTER] Raw packet (61 bytes): 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 -[2026-02-20T18:15:52.813612] LOG: [RX FILTER] Header: 0x15 | PathLength: 9 | SNR: 11.75 -[2026-02-20T18:15:52.813621] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:15:52.813630] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:52.813639] LOG: [RX FILTER] Channel hash: 0xad -[2026-02-20T18:15:52.813645] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad -[2026-02-20T18:15:52.813690] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:52.813700] LOG: [RX LOG] Dropped packet hex: 15 09 D4 5E CA 29 1F 7A DB 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 F1 -[2026-02-20T18:15:53.103440] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:15:53.103569] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:15:53.103593] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771640452} -[2026-02-20T18:15:53.103615] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:15:53.103643] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:15:53.106866] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:15:53.106890] LOG: [APP] Upload success: +1 items (total: 53) -[2026-02-20T18:15:56.800706] LOG: [GPS SERVICE] Position stream fired: lat=47.35815, lon=-122.11296, accuracy=3.8m -[2026-02-20T18:15:56.800747] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:15:56.800809] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:15:56.861670] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:15:56.861762] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:15:57.602692] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:15:57.602827] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:15:57.676782] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:15:57.676912] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:15:57.676943] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:15:57.676960] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:15:57.735416] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0e 00 00 00 92 23 00 00 -[2026-02-20T18:15:57.735537] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:15:57.735563] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:15:58.108119] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:15:58.470341] LOG: [CONN] Frame received (68 bytes): 88 30 bd 15 0e d4 5e ca 29 1f 7a c5 75 20 20 75 7e 1b cc ad f7 34 05 f8 da eb f3 50 8d de f4 ba 96 ed ef c8 7b 67 07 7f 94 f4 32 13 77 e3 ec 2e 2a ab 04 90 af c1 c5 a1 90 0f df 6a 0d 8f 63 e9 9c 6a 99 f5 -[2026-02-20T18:15:58.470464] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:15:58.470494] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:15:58.470713] LOG: [RX PARSE] RAW Packet (65 bytes): 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 -[2026-02-20T18:15:58.470732] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:15:58.470749] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:15:58.470780] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xd4, lastHop=0xcc, SNR=12.0, RSSI=-67, payload=49 bytes -[2026-02-20T18:15:58.470799] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:15:58.470811] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:15:58.470820] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:15:58.470884] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:15:58.470896] LOG: [RX FILTER] Raw packet (65 bytes): 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 -[2026-02-20T18:15:58.470919] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.0 -[2026-02-20T18:15:58.470934] LOG: [RX FILTER] ✓ RSSI OK (-67 < -30) -[2026-02-20T18:15:58.470950] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:15:58.470962] LOG: [RX FILTER] Channel hash: 0xad -[2026-02-20T18:15:58.470973] LOG: [RX FILTER] ❌ DROPPED: Unknown channel hash 0xad -[2026-02-20T18:15:58.471115] LOG: [RX LOG] ❌ Packet dropped: unknown channel hash -[2026-02-20T18:15:58.471128] LOG: [RX LOG] Dropped packet hex: 15 0E D4 5E CA 29 1F 7A C5 75 20 20 75 7E 1B CC AD F7 34 05 F8 DA EB F3 50 8D DE F4 BA 96 ED EF C8 7B 67 07 7F 94 F4 32 13 77 E3 EC 2E 2A AB 04 90 AF C1 C5 A1 90 0F DF 6A 0D 8F 63 E9 9C 6A 99 F5 -[2026-02-20T18:16:00.947965] LOG: [CONN] Frame received (91 bytes): 88 2e c4 15 03 e8 32 cc 81 c5 f8 81 89 60 a8 2e a8 74 e5 95 56 88 da 43 77 24 26 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 11 22 f1 b2 cc 75 0f c2 67 e9 2c cc cb 97 2b 25 88 be d9 da 65 9d a9 11 6c ca 96 d1 da e9 31 e3 -[2026-02-20T18:16:00.948119] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:00.948150] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:00.948235] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 32 CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 31 E3 -[2026-02-20T18:16:00.948255] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:16:00.948271] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:16:00.948302] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xcc, SNR=11.5, RSSI=-60, payload=83 bytes -[2026-02-20T18:16:00.948320] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:16:00.948333] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:00.948343] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:00.948423] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:16:00.948441] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 32 CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 31 E3 -[2026-02-20T18:16:00.948464] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.5 -[2026-02-20T18:16:00.948480] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:16:00.948491] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:16:00.948506] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:16:00.948519] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:16:00.948530] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:16:00.948546] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:16:00.948654] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:16:00.948822] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.35457, -122.50367 [..." -[2026-02-20T18:16:00.948849] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:16:00.948859] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:16:00.948889] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=3 -[2026-02-20T18:16:00.948900] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:16:00.948921] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 -[2026-02-20T18:16:00.948939] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:16:00.948959] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:16:00.948985] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.35815,-122.11296 -[2026-02-20T18:16:00.949004] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:16:00.949029] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35815,-122.11296 (batch tracking: 1 repeaters, rxCount: 28) -[2026-02-20T18:16:00.949052] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:16:00.949078] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.35815,-122.11296 -[2026-02-20T18:16:00.949531] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:16:00.949549] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:16:00.949561] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:16:01.770846] LOG: [GPS SERVICE] Position stream fired: lat=47.35815, lon=-122.11226, accuracy=3.8m -[2026-02-20T18:16:01.770905] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:16:01.770917] LOG: [RX BATCH] Distance check for repeater CC: 53.19m from first observation (threshold=25m) -[2026-02-20T18:16:01.770922] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:16:01.770925] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:16:01.770930] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:16:01.770938] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.35815,-122.11296 -[2026-02-20T18:16:01.770943] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:16:01.770946] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.35815,-122.11296 -[2026-02-20T18:16:01.770955] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 -[2026-02-20T18:16:01.770960] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:16:01.770965] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=3 -[2026-02-20T18:16:01.771033] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:16:01.771037] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:16:02.602989] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:02.651215] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0e 00 00 00 92 23 00 00 -[2026-02-20T18:16:02.651290] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:02.651302] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:06.768095] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11166, accuracy=3.8m -[2026-02-20T18:16:07.573994] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:16:07.574336] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:16:07.574352] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:16:07.575628] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:16:07.602629] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:07.663938] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2e 0e 00 00 00 92 23 00 00 -[2026-02-20T18:16:07.664076] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:07.664098] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:08.146965] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:16:08.147044] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:16:08.147067] LOG: [API] Response (200) in 0.57s: {"success":true,"expires_at":1771640467} -[2026-02-20T18:16:08.147086] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:16:08.147109] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:16:08.147544] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:16:08.147569] LOG: [APP] Upload success: +1 items (total: 54) -[2026-02-20T18:16:08.955576] LOG: [CONN] Frame received (98 bytes): 88 33 c4 15 0c e8 7e 38 75 20 20 20 75 38 7e 1b cc 81 c5 f8 81 89 60 a8 2e a8 74 e5 95 56 88 da 43 77 24 26 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 11 22 f1 b2 cc 75 0f c2 67 e9 2c cc cb 97 2b 25 88 be d9 da 65 9d a9 11 6c ca 96 d1 da e9 -[2026-02-20T18:16:08.955733] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:08.955767] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:08.955851] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 -[2026-02-20T18:16:08.955877] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:16:08.955893] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:16:08.955927] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xe8, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=81 bytes -[2026-02-20T18:16:08.955947] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:16:08.955960] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:08.955970] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:08.956057] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:16:08.956072] LOG: [RX FILTER] Raw packet (95 bytes): 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 -[2026-02-20T18:16:08.956099] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 12.75 -[2026-02-20T18:16:08.956114] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:16:08.956126] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:16:08.956144] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:16:08.956157] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:16:08.956183] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:16:08.956194] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:16:08.956406] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:16:08.956460] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:16:08.956708] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:16:08.956844] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:16:08.956860] LOG: [RX LOG] Dropped packet hex: 15 0C E8 7E 38 75 20 20 20 75 38 7E 1B CC 81 C5 F8 81 89 60 A8 2E A8 74 E5 95 56 88 DA 43 77 24 26 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 11 22 F1 B2 CC 75 0F C2 67 E9 2C CC CB 97 2B 25 88 BE D9 DA 65 9D A9 11 6C CA 96 D1 DA E9 -[2026-02-20T18:16:11.777817] LOG: [GPS SERVICE] Position stream fired: lat=47.35814, lon=-122.11107, accuracy=3.8m -[2026-02-20T18:16:12.604404] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:12.765197] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 93 23 00 00 -[2026-02-20T18:16:12.765354] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:12.765382] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:13.149130] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:16:16.767411] LOG: [GPS SERVICE] Position stream fired: lat=47.35812, lon=-122.11033, accuracy=3.8m -[2026-02-20T18:16:17.602973] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:17.775029] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0e 00 00 00 93 23 00 00 -[2026-02-20T18:16:17.775143] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:17.775162] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:21.786466] LOG: [GPS SERVICE] Position stream fired: lat=47.35808, lon=-122.10949, accuracy=3.8m -[2026-02-20T18:16:21.846289] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:16:21.846411] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:16:21.846434] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:16:21.846470] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:16:21.846612] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35808, -122.10949 [0.3w]" -[2026-02-20T18:16:21.846726] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:16:21.846735] LOG: [TX LOG] Payload: "@[MapperBot] 47.35808, -122.10949 [0.3w]" -[2026-02-20T18:16:21.846749] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:16:21.846758] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:16:21.846767] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:16:21.846779] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:16:21.846795] LOG: [CONN] Sending ping: @[MapperBot] 47.35808, -122.10949 [0.3w] -[2026-02-20T18:16:22.031] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:16:22.031052] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:16:22.031055] LOG: [CONN] Received OK response -[2026-02-20T18:16:22.576739] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:16:22.576893] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:16:22.602835] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:22.694884] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:22.695010] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:22.695031] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:23.938428] LOG: [CONN] Frame received (73 bytes): 88 33 c2 15 01 cc 81 d4 11 29 66 7f 4f 30 31 c3 31 89 a7 b8 00 26 03 81 d3 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 a3 d1 db 1c e5 94 17 2e 4c a1 04 04 1d 8f 64 a7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:16:23.938633] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:23.938672] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:23.938739] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:16:23.938760] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:16:23.938771] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:16:23.938807] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-62, payload=67 bytes -[2026-02-20T18:16:23.938821] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:16:23.938835] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:16:23.938847] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-62 -[2026-02-20T18:16:23.938857] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:16:23.938871] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:16:23.938883] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:23.938893] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:23.938909] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:16:25.032816] LOG: [PING] Ping sent successfully -[2026-02-20T18:16:26.771771] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.10834, accuracy=3.8m -[2026-02-20T18:16:26.847870] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:16:27.604391] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:16:27.604594] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:27.737982] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:16:27.738092] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:16:27.738112] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:16:27.738125] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T18:16:27.793156] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 33 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:27.793288] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:27.793308] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:30.034392] LOG: [PING] RX listening window ended -[2026-02-20T18:16:30.034607] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:16:30.034756] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:16:30.034873] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:16:30.034889] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:16:30.034904] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:16:30.034946] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:16:30.034962] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:16:30.035509] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:16:30.764428] LOG: [CONN] Frame received (82 bytes): 88 30 c4 15 0a cc 32 c7 7e 7a 17 7e c7 32 cc 81 d4 11 29 66 7f 4f 30 31 c3 31 89 a7 b8 00 26 03 81 d3 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 a3 d1 db 1c e5 94 17 2e 4c a1 04 04 1d 8f 64 a7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d 37 -[2026-02-20T18:16:30.764595] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:30.764627] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:30.764705] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0A CC 32 C7 7E 7A 17 7E C7 32 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D 37 -[2026-02-20T18:16:30.764727] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:16:30.764738] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:16:30.764767] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xcc, lastHop=0xcc, SNR=12.0, RSSI=-60, payload=67 bytes -[2026-02-20T18:16:30.764780] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:16:30.764794] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:30.764805] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:30.764818] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater 32 -[2026-02-20T18:16:30.764886] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:16:30.764910] LOG: [RX FILTER] Raw packet (79 bytes): 15 0A CC 32 C7 7E 7A 17 7E C7 32 CC 81 D4 11 29 66 7F 4F 30 31 C3 31 89 A7 B8 00 26 03 81 D3 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 A3 D1 DB 1C E5 94 17 2E 4C A1 04 04 1D 8F 64 A7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D 37 -[2026-02-20T18:16:30.764928] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.0 -[2026-02-20T18:16:30.764943] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:16:30.764954] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:16:30.764964] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:16:30.765044] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:16:30.765057] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:16:30.765069] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:16:30.765164] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:16:30.765358] LOG: [RX FILTER] Decrypted message (58 chars): "Cozmo: @[MapperBot] 47.35808, -122.10949 [0aDss;T}" -[2026-02-20T18:16:30.765384] LOG: [RX FILTER] Printable ratio: 86.2% (threshold: 60.0%) -[2026-02-20T18:16:30.765393] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:16:30.765427] LOG: [RX LOG] Packet heard via underlying hop: 32, SNR=null, path_length=10 (CARpeater stripped) -[2026-02-20T18:16:30.765443] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:16:30.765461] LOG: [RX BATCH] First observation for repeater 32: SNR=null -[2026-02-20T18:16:30.765557] LOG: [RX BATCH] Started 30s timeout timer for repeater 32 -[2026-02-20T18:16:30.765612] LOG: [RX BATCH] Distance check for repeater 32: 0.00m from first observation (threshold=25m) -[2026-02-20T18:16:30.765640] LOG: [APP] Immediate RX observation: repeater=32, snr=null, location=47.35806,-122.10834 -[2026-02-20T18:16:30.765678] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:16:30.765702] LOG: [APP] Created IMMEDIATE RX pin for repeater: 32 at 47.35806,-122.10834 (batch tracking: 1 repeaters, rxCount: 29) -[2026-02-20T18:16:30.765731] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:16:30.765752] LOG: [RX LOG] ✅ Observation kept in batch: repeater=32, snr=null, location=47.35806,-122.10834 -[2026-02-20T18:16:31.791056] LOG: [GPS SERVICE] Position stream fired: lat=47.35806, lon=-122.10710, accuracy=3.8m -[2026-02-20T18:16:31.791098] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:16:31.791120] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:16:31.791130] LOG: [RX BATCH] Distance check for repeater 32: 93.43m from first observation (threshold=25m) -[2026-02-20T18:16:31.791133] LOG: [RX BATCH] Distance threshold met for repeater 32, marking for flush -[2026-02-20T18:16:31.791135] LOG: [RX BATCH] Flushing repeater 32 -[2026-02-20T18:16:31.791141] LOG: [RX BATCH] Cleared timeout timer for repeater 32 -[2026-02-20T18:16:31.791145] LOG: [RX BATCH] Posting repeater 32: snr=null, location=47.35806,-122.10834 -[2026-02-20T18:16:31.791148] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:16:31.791153] LOG: [APP] Finalized RX entry (best SNR): repeater=32, snr=null, location=47.35806,-122.10834 -[2026-02-20T18:16:31.791158] LOG: [APP] RX pin SNR unchanged for repeater=32: batch best null <= pin 0.00 -[2026-02-20T18:16:31.791164] LOG: [APP] Cleared batch tracking for 32: wasPresent=true, remaining=0 -[2026-02-20T18:16:31.791168] LOG: [APP] Added RX log entry: repeater=32, snr=null, pathLen=10 -[2026-02-20T18:16:31.791217] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:16:31.791233] LOG: [RX BATCH] Repeater 32 removed from buffer -[2026-02-20T18:16:31.791237] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:16:32.603073] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:32.774188] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 30 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:32.774316] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:32.774340] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:16:35.036647] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:16:35.036906] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:16:35.036922] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:16:35.036935] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:16:35.037850] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:16:35.803675] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:16:35.803740] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:16:35.803754] LOG: [API] Response (200) in 0.77s: {"success":true,"expires_at":1771640495} -[2026-02-20T18:16:35.803772] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:16:35.803786] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:16:35.804413] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:16:35.804428] LOG: [APP] Upload success: +2 items (total: 56) -[2026-02-20T18:16:36.777282] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.10580, accuracy=3.8m -[2026-02-20T18:16:37.573781] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:16:37.573888] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:16:37.602894] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:37.785177] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:37.785320] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:37.785339] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:40.804759] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:16:41.810217] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.10461, accuracy=3.8m -[2026-02-20T18:16:42.602958] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:42.793661] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 30 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:42.793755] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:42.793766] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:46.648717] LOG: [CONN] Frame received (29 bytes): 88 2f c2 05 04 f9 e0 7e cc 43 83 e2 ba 9c 5a b8 8c d8 78 21 da a1 64 23 24 70 be 6f 25 -[2026-02-20T18:16:46.648772] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:46.648811] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:46.648850] LOG: [RX PARSE] RAW Packet (26 bytes): 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 -[2026-02-20T18:16:46.648877] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T18:16:46.648888] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:16:46.648918] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=4, firstHop=0xf9, lastHop=0xcc, SNR=11.75, RSSI=-62, payload=20 bytes -[2026-02-20T18:16:46.648939] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=4 -[2026-02-20T18:16:46.648949] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:46.648958] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:46.648996] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:16:46.649015] LOG: [RX FILTER] Raw packet (26 bytes): 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 -[2026-02-20T18:16:46.649033] LOG: [RX FILTER] Header: 0x05 | PathLength: 4 | SNR: 11.75 -[2026-02-20T18:16:46.649053] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:16:46.649068] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) -[2026-02-20T18:16:46.649219] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:16:46.649238] LOG: [RX LOG] Dropped packet hex: 05 04 F9 E0 7E CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F 25 -[2026-02-20T18:16:46.780654] LOG: [GPS SERVICE] Position stream fired: lat=47.35798, lon=-122.10365, accuracy=3.8m -[2026-02-20T18:16:47.604025] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:47.745856] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2f 0f 00 00 00 93 23 00 00 -[2026-02-20T18:16:47.746004] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:47.746029] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:49.035455] LOG: [CONN] Frame received (35 bytes): 88 31 c4 05 0b f9 e0 7e 75 20 20 75 24 7e db cc 43 83 e2 ba 9c 5a b8 8c d8 78 21 da a1 64 23 24 70 be 6f -[2026-02-20T18:16:49.035600] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:16:49.035636] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:16:49.035673] LOG: [RX PARSE] RAW Packet (32 bytes): 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F -[2026-02-20T18:16:49.035684] LOG: [RX PARSE] Header: 0x05, Route type: 1 -[2026-02-20T18:16:49.035698] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:16:49.035725] LOG: [RX PARSE] Parsed metadata: header=0x05, pathLength=11, firstHop=0xf9, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=19 bytes -[2026-02-20T18:16:49.035740] LOG: [UNIFIED RX] Packet received: header=0x5, pathLength=11 -[2026-02-20T18:16:49.035749] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:16:49.035756] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:16:49.035789] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:16:49.035803] LOG: [RX FILTER] Raw packet (32 bytes): 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F -[2026-02-20T18:16:49.035816] LOG: [RX FILTER] Header: 0x05 | PathLength: 11 | SNR: 12.25 -[2026-02-20T18:16:49.035831] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:16:49.035844] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x05) -[2026-02-20T18:16:49.035882] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:16:49.035896] LOG: [RX LOG] Dropped packet hex: 05 0B F9 E0 7E 75 20 20 75 24 7E DB CC 43 83 E2 BA 9C 5A B8 8C D8 78 21 DA A1 64 23 24 70 BE 6F -[2026-02-20T18:16:51.774664] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.10270, accuracy=3.9m -[2026-02-20T18:16:52.573740] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:16:52.573907] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:16:52.605252] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:52.692671] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0f 00 00 00 94 23 00 00 -[2026-02-20T18:16:52.692759] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:52.692770] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:16:56.787903] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.10178, accuracy=3.8m -[2026-02-20T18:16:57.603022] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:16:57.603263] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:16:57.704225] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:16:57.704365] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:16:57.704385] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:16:57.704402] LOG: [CONN] Battery updated: 4069mV (89%) -[2026-02-20T18:16:57.766501] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 0f 00 00 00 94 23 00 00 -[2026-02-20T18:16:57.766807] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:16:57.766833] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:00.036417] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:17:00.036564] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:17:00.036585] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:17:00.036624] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:17:00.036666] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35801, -122.10178 [0.3w]" -[2026-02-20T18:17:00.036676] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:17:00.036686] LOG: [TX LOG] Payload: "@[MapperBot] 47.35801, -122.10178 [0.3w]" -[2026-02-20T18:17:00.036697] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:17:00.036708] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:17:00.036722] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:17:00.036731] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:17:00.036759] LOG: [CONN] Sending ping: @[MapperBot] 47.35801, -122.10178 [0.3w] -[2026-02-20T18:17:00.223794] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:17:00.223936] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:17:00.223949] LOG: [CONN] Received OK response -[2026-02-20T18:17:01.544080] LOG: [CONN] Frame received (73 bytes): 88 2f c4 15 01 cc 81 32 1f 4e 91 be a8 4a 50 2b 96 e4 ee c4 5b 0d fd 34 ff ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 ce 86 99 d1 97 94 0b 8f 97 09 5a d1 2a 13 85 21 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:17:01.544123] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:17:01.544148] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:17:01.544192] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 32 1F 4E 91 BE A8 4A 50 2B 96 E4 EE C4 5B 0D FD 34 FF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 CE 86 99 D1 97 94 0B 8F 97 09 5A D1 2A 13 85 21 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:17:01.544207] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:17:01.544213] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:17:01.544246] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-60, payload=67 bytes -[2026-02-20T18:17:01.544255] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:17:01.544264] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:17:01.544273] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-60 -[2026-02-20T18:17:01.544280] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:17:01.544290] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:17:01.544371] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:17:01.544383] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:17:01.544389] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:17:01.808741] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.10077, accuracy=4.1m -[2026-02-20T18:17:01.809185] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:17:01.809351] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:17:02.603127] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:02.653089] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:02.653193] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:02.653213] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:17:03.224935] LOG: [PING] Ping sent successfully -[2026-02-20T18:17:05.039877] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:17:06.771396] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09991, accuracy=4.1m -[2026-02-20T18:17:07.573768] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:17:07.573952] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:17:07.602741] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:07.663136] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:07.663231] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:07.663251] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:08.227533] LOG: [PING] RX listening window ended -[2026-02-20T18:17:08.227692] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:17:08.227728] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:17:08.227801] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:17:08.227814] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:17:08.227832] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:17:08.227857] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:17:08.227879] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:17:08.228298] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:17:11.784716] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09903, accuracy=4.3m -[2026-02-20T18:17:12.605286] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:12.731675] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:12.731762] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:12.731775] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:13.229649] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:17:13.229846] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:17:13.229863] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:17:13.783788] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:17:13.783919] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:17:13.783945] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771640533} -[2026-02-20T18:17:13.783963] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:17:13.783990] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:17:13.787558] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:17:13.787584] LOG: [APP] Upload success: +1 items (total: 57) -[2026-02-20T18:17:16.777358] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09806, accuracy=4.3m -[2026-02-20T18:17:17.603085] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:17.653357] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:17.653504] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:17.653524] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:18.788621] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:17:21.768858] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09721, accuracy=4.3m -[2026-02-20T18:17:22.575007] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:17:22.575159] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:17:22.602868] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:22.669085] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:22.669218] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:22.669238] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:26.788239] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09640, accuracy=4.3m -[2026-02-20T18:17:27.602887] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:17:27.603092] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:27.686346] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:17:27.686618] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:17:27.686626] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:17:27.686637] LOG: [CONN] Battery updated: 4069mV (89%) -[2026-02-20T18:17:27.747951] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:27.748025] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:27.748037] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:31.789047] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09537, accuracy=3.9m -[2026-02-20T18:17:32.602641] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:32.750968] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:32.751027] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:32.751033] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:36.783870] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09437, accuracy=3.9m -[2026-02-20T18:17:36.784012] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:17:36.784062] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:17:37.573685] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:17:37.573787] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:17:37.603437] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:37.752869] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c4 2f 0f 00 00 00 94 23 00 00 -[2026-02-20T18:17:37.752912] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:37.752916] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:17:38.228629] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:17:38.228684] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:17:38.228687] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:17:38.228700] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:17:38.228711] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35799, -122.09437 [0.3w]" -[2026-02-20T18:17:38.228712] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:17:38.228714] LOG: [TX LOG] Payload: "@[MapperBot] 47.35799, -122.09437 [0.3w]" -[2026-02-20T18:17:38.228716] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:17:38.228718] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:17:38.228721] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:17:38.228722] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:17:38.228726] LOG: [CONN] Sending ping: @[MapperBot] 47.35799, -122.09437 [0.3w] -[2026-02-20T18:17:38.412150] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:17:38.412179] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:17:38.412182] LOG: [CONN] Received OK response -[2026-02-20T18:17:40.436991] LOG: [CONN] Frame received (73 bytes): 88 31 c7 15 01 cc 81 cb 63 6c 6e 99 34 f4 b1 44 7d 6f 1a 07 3d b8 a7 40 25 65 60 fb 44 af b4 f1 10 e8 92 c3 03 28 a2 5e 12 d1 50 57 ae e4 51 a1 2e 49 be d6 07 d7 cc a1 23 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:17:40.437039] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:17:40.437047] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:17:40.437059] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 CB 63 6C 6E 99 34 F4 B1 44 7D 6F 1A 07 3D B8 A7 40 25 65 60 FB 44 AF B4 F1 10 E8 92 C3 03 28 A2 5E 12 D1 50 57 AE E4 51 A1 2E 49 BE D6 07 D7 CC A1 23 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:17:40.437061] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:17:40.437064] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:17:40.437069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=67 bytes -[2026-02-20T18:17:40.437072] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:17:40.437074] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:17:40.437076] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-57 -[2026-02-20T18:17:40.437078] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:17:40.437081] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:17:40.437083] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:17:40.437085] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:17:40.437086] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:17:41.412732] LOG: [PING] Ping sent successfully -[2026-02-20T18:17:41.773094] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09371, accuracy=3.8m -[2026-02-20T18:17:42.602632] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:42.735685] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:17:42.735741] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:42.735746] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:17:43.229598] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:17:46.413648] LOG: [PING] RX listening window ended -[2026-02-20T18:17:46.413688] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:17:46.413699] LOG: [GRAPH] Recorded txFail event at -119dBm -[2026-02-20T18:17:46.413729] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:17:46.413733] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:17:46.413737] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:17:46.413748] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:17:46.413753] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:17:46.414503] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:17:46.763751] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09308, accuracy=3.9m -[2026-02-20T18:17:47.602662] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:47.741449] LOG: [CONN] Frame received (14 bytes): 18 01 8b ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:17:47.741517] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:47.741523] LOG: [CONN] Noise floor updated: -117dBm -[2026-02-20T18:17:51.415603] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:17:51.415676] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:17:51.415682] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:17:52.021086] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:17:52.021114] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:17:52.021119] LOG: [API] Response (200) in 0.60s: {"success":true,"expires_at":1771640571} -[2026-02-20T18:17:52.021125] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:17:52.021130] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:17:52.021239] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:17:52.021244] LOG: [APP] Upload success: +1 items (total: 58) -[2026-02-20T18:17:52.108043] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.09245, accuracy=4.4m -[2026-02-20T18:17:52.573645] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:17:52.573717] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:17:52.602713] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:52.751362] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:17:52.751417] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:52.751423] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:17:57.021692] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:17:57.111270] LOG: [GPS SERVICE] Position stream fired: lat=47.35799, lon=-122.09199, accuracy=4.0m -[2026-02-20T18:17:57.602611] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:17:57.602687] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:17:57.761140] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:17:57.761207] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:17:57.761216] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:17:57.761224] LOG: [CONN] Battery updated: 4069mV (89%) -[2026-02-20T18:17:57.821272] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:17:57.821321] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:17:57.821330] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:02.103415] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.09148, accuracy=4.9m -[2026-02-20T18:18:02.602772] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:02.683784] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:02.683855] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:02.683867] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:07.099972] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.09070, accuracy=5.9m -[2026-02-20T18:18:07.100011] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:18:07.100062] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:18:07.573650] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:18:07.573743] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:18:07.602698] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:07.693747] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:07.693830] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:07.693839] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:11.763731] LOG: [GPS SERVICE] Position stream fired: lat=47.35800, lon=-122.08985, accuracy=5.0m -[2026-02-20T18:18:12.602717] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:12.700962] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:12.701014] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:12.701019] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:16.414742] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:18:16.414779] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:18:16.414789] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:18:16.414806] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:18:16.414825] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35800, -122.08985 [0.3w]" -[2026-02-20T18:18:16.414828] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:18:16.414830] LOG: [TX LOG] Payload: "@[MapperBot] 47.35800, -122.08985 [0.3w]" -[2026-02-20T18:18:16.414836] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:18:16.414840] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:18:16.414843] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:18:16.414847] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:18:16.414852] LOG: [CONN] Sending ping: @[MapperBot] 47.35800, -122.08985 [0.3w] -[2026-02-20T18:18:16.511181] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:18:16.511233] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:18:16.511237] LOG: [CONN] Received OK response -[2026-02-20T18:18:16.802946] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08934, accuracy=4.3m -[2026-02-20T18:18:17.602599] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:17.659394] LOG: [CONN] Frame received (73 bytes): 88 33 c4 15 01 cc 81 3f 6f 96 8c 3f f5 de 7d ff ea 43 7a 25 63 72 fd 29 63 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 8d 1e b9 6e f7 59 22 32 0a 19 af d3 11 30 98 7a 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:18:17.659445] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:17.659457] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:17.659477] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 3F 6F 96 8C 3F F5 DE 7D FF EA 43 7A 25 63 72 FD 29 63 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 8D 1E B9 6E F7 59 22 32 0A 19 AF D3 11 30 98 7A 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:18:17.659481] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:18:17.659485] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:18:17.659496] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-60, payload=67 bytes -[2026-02-20T18:18:17.659501] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:18:17.659505] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:18:17.659508] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-60 -[2026-02-20T18:18:17.659514] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:18:17.659516] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:18:17.659519] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:17.659523] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:17.659526] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:18:17.681157] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:17.681203] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:17.681209] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:19.511754] LOG: [PING] Ping sent successfully -[2026-02-20T18:18:21.415634] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:18:21.796561] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08919, accuracy=4.0m -[2026-02-20T18:18:22.573594] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:18:22.573657] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:18:22.602588] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:22.691016] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 33 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:22.691088] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:22.691097] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:24.512601] LOG: [PING] RX listening window ended -[2026-02-20T18:18:24.512669] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:18:24.512678] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:18:24.512708] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:18:24.512712] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:18:24.512717] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:18:24.512723] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:18:24.512729] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:18:24.512922] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:18:26.787082] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08886, accuracy=12.3m -[2026-02-20T18:18:27.315597] LOG: [CONN] Frame received (131 bytes): 88 31 c5 11 06 13 c7 32 74 7e cc 61 ff 86 b6 67 de 24 8f af 2d 91 48 a0 a8 b4 8f 9b 12 51 68 65 b4 cb 63 e9 43 60 fa 2f b9 08 1d e4 15 99 69 57 c7 55 55 43 f3 d7 0d ab a4 7d 08 80 22 9a a1 29 e1 98 97 1c ed 43 8e ba 31 e0 56 c0 3b 95 d5 5c c9 1a 03 de 29 0c 3f ff 40 f1 87 a9 49 20 4c 07 da 19 99 be db c5 06 59 0f 4a 47 fa ee ef 03 92 46 1a d4 02 72 14 b3 f8 56 61 73 68 6f 6e 2d 47 44 2d 31 -[2026-02-20T18:18:27.315659] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:27.315671] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:27.315699] LOG: [RX PARSE] RAW Packet (128 bytes): 11 06 13 C7 32 74 7E CC 61 FF 86 B6 67 DE 24 8F AF 2D 91 48 A0 A8 B4 8F 9B 12 51 68 65 B4 CB 63 E9 43 60 FA 2F B9 08 1D E4 15 99 69 57 C7 55 55 43 F3 D7 0D AB A4 7D 08 80 22 9A A1 29 E1 98 97 1C ED 43 8E BA 31 E0 56 C0 3B 95 D5 5C C9 1A 03 DE 29 0C 3F FF 40 F1 87 A9 49 20 4C 07 DA 19 99 BE DB C5 06 59 0F 4A 47 FA EE EF 03 92 46 1A D4 02 72 14 B3 F8 56 61 73 68 6F 6E 2D 47 44 2D 31 -[2026-02-20T18:18:27.315705] LOG: [RX PARSE] Header: 0x11, Route type: 1 -[2026-02-20T18:18:27.315708] LOG: [RX PARSE] Path length offset: 1, Path length: 6 -[2026-02-20T18:18:27.315715] LOG: [RX PARSE] Parsed metadata: header=0x11, pathLength=6, firstHop=0x13, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=120 bytes -[2026-02-20T18:18:27.315720] LOG: [UNIFIED RX] Packet received: header=0x11, pathLength=6 -[2026-02-20T18:18:27.315723] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:27.315726] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:27.315751] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:18:27.315753] LOG: [RX FILTER] Raw packet (128 bytes): 11 06 13 C7 32 74 7E CC 61 FF 86 B6 67 DE 24 8F AF 2D 91 48 A0 A8 B4 8F 9B 12 51 68 65 B4 CB 63 E9 43 60 FA 2F B9 08 1D E4 15 99 69 57 C7 55 55 43 F3 D7 0D AB A4 7D 08 80 22 9A A1 29 E1 98 97 1C ED 43 8E BA 31 E0 56 C0 3B 95 D5 5C C9 1A 03 DE 29 0C 3F FF 40 F1 87 A9 49 20 4C 07 DA 19 99 BE DB C5 06 59 0F 4A 47 FA EE EF 03 92 46 1A D4 02 72 14 B3 F8 56 61 73 68 6F 6E 2D 47 44 2D 31 -[2026-02-20T18:18:27.315759] LOG: [RX FILTER] Header: 0x11 | PathLength: 6 | SNR: 12.25 -[2026-02-20T18:18:27.315763] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:18:27.315767] LOG: [RX FILTER] Packet type: ADVERT (0x11) -[2026-02-20T18:18:27.315770] LOG: [RX FILTER] ADVERT flags: 0x92 -[2026-02-20T18:18:27.315772] LOG: [RX FILTER] ADVERT has lat/lon, skipping 8 bytes -[2026-02-20T18:18:27.315819] LOG: [RX FILTER] ADVERT name extracted: "Vashon-GD-1" (11 chars) -[2026-02-20T18:18:27.315826] LOG: [RX FILTER] ADVERT name printable ratio: 100.0% -[2026-02-20T18:18:27.315829] LOG: [RX FILTER] ✅ KEPT: ADVERT passed all validations (name="Vashon-GD-1") -[2026-02-20T18:18:27.315837] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=6 -[2026-02-20T18:18:27.315839] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:18:27.315846] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:18:27.315851] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:18:27.315879] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:18:27.315884] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.35801,-122.08886 -[2026-02-20T18:18:27.315891] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:18:27.315897] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35801,-122.08886 (batch tracking: 1 repeaters, rxCount: 30) -[2026-02-20T18:18:27.315904] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:18:27.315910] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.35801,-122.08886 -[2026-02-20T18:18:27.318705] LOG: [CONN] Frame received (148 bytes): 8a 61 ff 86 b6 67 de 24 8f af 2d 91 48 a0 a8 b4 8f 9b 12 51 68 65 b4 cb 63 e9 43 60 fa 2f b9 08 1d 02 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 61 73 68 6f 6e 2d 47 44 2d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e4 15 99 69 46 1a d4 02 72 14 b3 f8 f1 15 99 69 -[2026-02-20T18:18:27.318729] LOG: [CONN] Response code: 0x8a (138) -[2026-02-20T18:18:27.318734] LOG: [CONN] Unhandled frame: code=138 (0x8a) -[2026-02-20T18:18:27.602660] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:18:27.602772] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:27.672247] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:18:27.672313] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:18:27.672323] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:18:27.672331] LOG: [CONN] Battery updated: 4059mV (88%) -[2026-02-20T18:18:27.731231] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 95 23 00 00 -[2026-02-20T18:18:27.731296] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:27.731307] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:29.513645] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:18:29.513755] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:18:29.513760] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:18:30.073867] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:18:30.073896] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:18:30.073902] LOG: [API] Response (200) in 0.56s: {"success":true,"expires_at":1771640609} -[2026-02-20T18:18:30.073907] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:18:30.073915] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:18:30.074070] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:18:30.074076] LOG: [APP] Upload success: +1 items (total: 59) -[2026-02-20T18:18:31.301535] LOG: [CONN] Frame received (48 bytes): 88 31 c6 15 08 6b 98 64 13 e8 9d 1b cc ca fb bc 36 90 b8 f7 74 56 e3 e0 31 b6 50 e3 df 49 91 f6 d7 10 3b ef f8 86 1f 95 91 2a dd 1b 40 d9 0a e0 -[2026-02-20T18:18:31.301559] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:31.301576] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:31.301592] LOG: [RX PARSE] RAW Packet (45 bytes): 15 08 6B 98 64 13 E8 9D 1B CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A E0 -[2026-02-20T18:18:31.301598] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:18:31.301602] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:18:31.301615] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0x6b, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=35 bytes -[2026-02-20T18:18:31.301620] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:18:31.301622] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:31.301627] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:31.301644] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:18:31.301647] LOG: [RX FILTER] Raw packet (45 bytes): 15 08 6B 98 64 13 E8 9D 1B CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A E0 -[2026-02-20T18:18:31.301654] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 -[2026-02-20T18:18:31.301658] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:18:31.301662] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:18:31.301666] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:18:31.301670] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:18:31.301673] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:18:31.301679] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:18:31.301702] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:18:31.301775] LOG: [RX FILTER] Decrypted message (22 chars): " Andrew KI7PXC L1: T" -[2026-02-20T18:18:31.301783] LOG: [RX FILTER] Printable ratio: 90.9% (threshold: 60.0%) -[2026-02-20T18:18:31.301785] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:18:31.301835] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=8 -[2026-02-20T18:18:31.301841] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:18:31.301847] LOG: [RX BATCH] Ignoring worse SNR for repeater CC: current=12.25, new=12.25 -[2026-02-20T18:18:31.301882] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:18:31.301888] LOG: [RX LOG] ⏭️ Observation ignored (worse SNR): repeater=CC, snr=12.25, current_best=12.25 -[2026-02-20T18:18:31.781263] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.08817, accuracy=3.8m -[2026-02-20T18:18:31.781359] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:18:31.781373] LOG: [RX BATCH] Distance check for repeater CC: 52.06m from first observation (threshold=25m) -[2026-02-20T18:18:31.781376] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:18:31.781379] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:18:31.781431] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:18:31.781437] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.35801,-122.08886 -[2026-02-20T18:18:31.781441] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:18:31.781447] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.35801,-122.08886 -[2026-02-20T18:18:31.781453] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:18:31.781462] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:18:31.781465] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=6 -[2026-02-20T18:18:31.781483] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:18:31.781486] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:18:32.602722] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:32.715051] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 0f 00 00 00 96 23 00 00 -[2026-02-20T18:18:32.715129] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:32.715138] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:33.853579] LOG: [CONN] Frame received (52 bytes): 88 31 c5 15 0d 6b 98 64 13 e8 7e 75 20 20 75 53 7e cc ca fb bc 36 90 b8 f7 74 56 e3 e0 31 b6 50 e3 df 49 91 f6 d7 10 3b ef f8 86 1f 95 91 2a dd 1b 40 d9 0a -[2026-02-20T18:18:33.853632] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:33.853642] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:33.853656] LOG: [RX PARSE] RAW Packet (49 bytes): 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A -[2026-02-20T18:18:33.853660] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:18:33.853665] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:18:33.853672] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0x6b, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=34 bytes -[2026-02-20T18:18:33.853677] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:18:33.853680] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:33.853682] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:33.853694] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:18:33.853697] LOG: [RX FILTER] Raw packet (49 bytes): 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A -[2026-02-20T18:18:33.853702] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.25 -[2026-02-20T18:18:33.853706] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:18:33.853709] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:18:33.853712] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:18:33.853716] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:18:33.853719] LOG: [RX FILTER] Encrypted message: 31 bytes -[2026-02-20T18:18:33.853722] LOG: [CRYPTO] Decrypting message (31 bytes) -[2026-02-20T18:18:33.853777] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:18:33.853791] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:18:33.853861] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:18:33.853887] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:18:33.853889] LOG: [RX LOG] Dropped packet hex: 15 0D 6B 98 64 13 E8 7E 75 20 20 75 53 7E CC CA FB BC 36 90 B8 F7 74 56 E3 E0 31 B6 50 E3 DF 49 91 F6 D7 10 3B EF F8 86 1F 95 91 2A DD 1B 40 D9 0A -[2026-02-20T18:18:35.074635] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:18:37.110633] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08718, accuracy=3.8m -[2026-02-20T18:18:37.110677] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:18:37.110781] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:18:37.574611] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:18:37.574729] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:18:37.574736] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:18:37.575099] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:18:37.602692] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:37.661273] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 96 23 00 00 -[2026-02-20T18:18:37.661339] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:37.661347] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:37.833840] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:18:37.833872] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:18:37.833877] LOG: [API] Response (200) in 0.26s: {"success":true,"expires_at":1771640617} -[2026-02-20T18:18:37.833882] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:18:37.833893] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:18:37.834052] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:18:37.834059] LOG: [APP] Upload success: +1 items (total: 60) -[2026-02-20T18:18:41.780856] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.08625, accuracy=4.0m -[2026-02-20T18:18:42.602645] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:42.671206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 0f 00 00 00 96 23 00 00 -[2026-02-20T18:18:42.671274] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:42.671280] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:42.834733] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:18:42.859899] LOG: [CONN] Frame received (44 bytes): 88 2e c2 15 04 32 5c db cc 05 40 9a 68 cd 0a a6 27 17 33 c9 ec 94 1a 2c fc 05 dd 73 81 82 76 50 00 0d 86 88 36 c3 3b dd 56 af a6 71 -[2026-02-20T18:18:42.859943] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:42.859958] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:42.859971] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 32 5C DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 81 82 76 50 00 0D 86 88 36 C3 3B DD 56 AF A6 71 -[2026-02-20T18:18:42.859976] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:18:42.859978] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:18:42.859990] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x32, lastHop=0xcc, SNR=11.5, RSSI=-62, payload=35 bytes -[2026-02-20T18:18:42.859995] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:18:42.859997] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:42.859999] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:42.860011] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:18:42.860016] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 32 5C DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 81 82 76 50 00 0D 86 88 36 C3 3B DD 56 AF A6 71 -[2026-02-20T18:18:42.860021] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.5 -[2026-02-20T18:18:42.860027] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:18:42.860030] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:18:42.860034] LOG: [RX FILTER] Channel hash: 0x05 -[2026-02-20T18:18:42.860039] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma -[2026-02-20T18:18:42.860042] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:18:42.860047] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:18:42.860068] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:18:42.860128] LOG: [RX FILTER] Decrypted message (17 chars): "AlanHelTxt : T" -[2026-02-20T18:18:42.860137] LOG: [RX FILTER] Printable ratio: 88.2% (threshold: 60.0%) -[2026-02-20T18:18:42.860139] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:18:42.860149] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=4 -[2026-02-20T18:18:42.860152] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:18:42.860158] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 -[2026-02-20T18:18:42.860161] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:18:42.860168] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:18:42.860174] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.35803,-122.08625 -[2026-02-20T18:18:42.860180] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:18:42.860191] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35803,-122.08625 (batch tracking: 1 repeaters, rxCount: 31) -[2026-02-20T18:18:42.860199] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:18:42.860207] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.35803,-122.08625 -[2026-02-20T18:18:46.809087] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08523, accuracy=3.8m -[2026-02-20T18:18:46.809139] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:18:46.809151] LOG: [RX BATCH] Distance check for repeater CC: 76.76m from first observation (threshold=25m) -[2026-02-20T18:18:46.809154] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:18:46.809157] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:18:46.809165] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:18:46.809170] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.35803,-122.08625 -[2026-02-20T18:18:46.809173] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:18:46.809178] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.35803,-122.08625 -[2026-02-20T18:18:46.809183] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 -[2026-02-20T18:18:46.809190] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:18:46.809195] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=4 -[2026-02-20T18:18:46.809248] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:18:46.809253] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:18:47.603225] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:47.713079] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2e 0f 00 00 00 96 23 00 00 -[2026-02-20T18:18:47.713138] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:47.713149] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:51.791147] LOG: [GPS SERVICE] Position stream fired: lat=47.35802, lon=-122.08426, accuracy=4.1m -[2026-02-20T18:18:52.573605] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:18:52.573712] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:18:52.573717] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:18:52.574049] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:18:52.602800] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:52.722360] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2e 0f 00 00 00 96 23 00 00 -[2026-02-20T18:18:52.722430] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:52.722440] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:53.101423] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:18:53.101451] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:18:53.101454] LOG: [API] Response (200) in 0.53s: {"success":true,"expires_at":1771640632} -[2026-02-20T18:18:53.101461] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:18:53.101466] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:18:53.101560] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:18:53.101565] LOG: [APP] Upload success: +1 items (total: 61) -[2026-02-20T18:18:54.513649] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:18:54.513719] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:18:54.513724] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:18:54.513742] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:18:54.513758] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35802, -122.08426 [0.3w]" -[2026-02-20T18:18:54.513762] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:18:54.513764] LOG: [TX LOG] Payload: "@[MapperBot] 47.35802, -122.08426 [0.3w]" -[2026-02-20T18:18:54.513768] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:18:54.513772] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:18:54.513775] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:18:54.513777] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:18:54.513785] LOG: [CONN] Sending ping: @[MapperBot] 47.35802, -122.08426 [0.3w] -[2026-02-20T18:18:54.581018] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:18:54.581088] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:18:54.581095] LOG: [CONN] Received OK response -[2026-02-20T18:18:56.368366] LOG: [CONN] Frame received (73 bytes): 88 32 c5 15 01 cc 81 fc a0 36 78 af 7c c5 91 75 14 d3 61 8c c9 4b ea 99 63 ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 9c d4 d0 64 82 45 a1 7f cf b8 51 71 13 51 c5 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:18:56.368394] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:18:56.368414] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:18:56.368440] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 FC A0 36 78 AF 7C C5 91 75 14 D3 61 8C C9 4B EA 99 63 CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 9C D4 D0 64 82 45 A1 7F CF B8 51 71 13 51 C5 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:18:56.368449] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:18:56.368453] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:18:56.368473] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-59, payload=67 bytes -[2026-02-20T18:18:56.368478] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:18:56.368482] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:18:56.368489] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-59 -[2026-02-20T18:18:56.368492] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:18:56.368497] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:18:56.368551] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:18:56.368556] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:18:56.368563] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:18:56.772474] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.08325, accuracy=4.6m -[2026-02-20T18:18:57.582052] LOG: [PING] Ping sent successfully -[2026-02-20T18:18:57.602786] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:18:57.602848] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:18:57.761600] LOG: [CONN] Frame received (11 bytes): 0c e9 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:18:57.761658] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:18:57.761663] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:18:57.761667] LOG: [CONN] Battery updated: 4073mV (89%) -[2026-02-20T18:18:57.826371] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 32 10 00 00 00 96 23 00 00 -[2026-02-20T18:18:57.826416] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:18:57.826421] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:18:58.102684] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:18:59.514643] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:19:00.657398] LOG: [CONN] Frame received (57 bytes): 88 2f c5 15 21 32 3e 9d 0a 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 ee fd 20 22 1f ab 7e 02 db cc 05 40 9a 68 cd 0a a6 27 17 33 c9 ec 94 1a 2c fc 05 dd 73 -[2026-02-20T18:19:00.657457] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:19:00.657469] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:19:00.657488] LOG: [RX PARSE] RAW Packet (54 bytes): 15 21 32 3E 9D 0A 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 22 1F AB 7E 02 DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 -[2026-02-20T18:19:00.657493] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:19:00.657499] LOG: [RX PARSE] Path length offset: 1, Path length: 33 -[2026-02-20T18:19:00.657513] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=33, firstHop=0x32, lastHop=0xcc, SNR=11.75, RSSI=-59, payload=19 bytes -[2026-02-20T18:19:00.657519] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=33 -[2026-02-20T18:19:00.657522] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:19:00.657525] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:19:00.657544] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:19:00.657547] LOG: [RX FILTER] Raw packet (54 bytes): 15 21 32 3E 9D 0A 53 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 EE FD 20 22 1F AB 7E 02 DB CC 05 40 9A 68 CD 0A A6 27 17 33 C9 EC 94 1A 2C FC 05 DD 73 -[2026-02-20T18:19:00.657555] LOG: [RX FILTER] Header: 0x15 | PathLength: 33 | SNR: 11.75 -[2026-02-20T18:19:00.657560] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:19:00.657566] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:19:00.657569] LOG: [RX FILTER] Channel hash: 0x05 -[2026-02-20T18:19:00.657574] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma -[2026-02-20T18:19:00.657580] LOG: [RX FILTER] Encrypted message: 16 bytes -[2026-02-20T18:19:00.657584] LOG: [CRYPTO] Decrypting message (16 bytes) -[2026-02-20T18:19:00.657607] LOG: [CRYPTO] Decrypted successfully (16 bytes) -[2026-02-20T18:19:00.657676] LOG: [RX FILTER] Decrypted message (10 chars): "AlanHelTxt" -[2026-02-20T18:19:00.657684] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:19:00.657687] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:19:00.657752] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=33 -[2026-02-20T18:19:00.657757] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:19:00.657764] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 -[2026-02-20T18:19:00.657772] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:19:00.657782] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:19:00.657789] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.35803,-122.08325 -[2026-02-20T18:19:00.657797] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:19:00.657807] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35803,-122.08325 (batch tracking: 1 repeaters, rxCount: 32) -[2026-02-20T18:19:00.657817] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:19:00.657824] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.35803,-122.08325 -[2026-02-20T18:19:02.112128] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08215, accuracy=4.1m -[2026-02-20T18:19:02.112166] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:19:02.112177] LOG: [RX BATCH] Distance check for repeater CC: 82.98m from first observation (threshold=25m) -[2026-02-20T18:19:02.112180] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:19:02.112183] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:19:02.112188] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:19:02.112192] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.35803,-122.08325 -[2026-02-20T18:19:02.112201] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:19:02.112204] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.35803,-122.08325 -[2026-02-20T18:19:02.112210] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 -[2026-02-20T18:19:02.112216] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:19:02.112222] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=33 -[2026-02-20T18:19:02.112283] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:19:02.112286] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:19:02.582807] LOG: [PING] RX listening window ended -[2026-02-20T18:19:02.582931] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:19:02.582947] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:19:02.582999] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:19:02.583004] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:19:02.583015] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:19:02.583086] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:19:02.583096] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:19:02.592524] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:19:02.605152] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:02.652308] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 10 00 00 00 96 23 00 00 -[2026-02-20T18:19:02.652375] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:02.652386] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:07.101275] LOG: [GPS SERVICE] Position stream fired: lat=47.35805, lon=-122.08105, accuracy=4.0m -[2026-02-20T18:19:07.573738] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:19:07.573901] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:19:07.573911] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:19:07.573917] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:19:07.574467] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:19:07.598751] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:19:07.598798] LOG: [API QUEUE] Upload skipped: already uploading -[2026-02-20T18:19:07.606055] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:07.661880] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 10 00 00 00 96 23 00 00 -[2026-02-20T18:19:07.661945] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:07.661954] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:08.094375] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:19:08.094405] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:19:08.094412] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771640647} -[2026-02-20T18:19:08.094417] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:19:08.094425] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:19:08.097820] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:19:08.097843] LOG: [APP] Upload success: +2 items (total: 63) -[2026-02-20T18:19:12.116953] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07998, accuracy=3.8m -[2026-02-20T18:19:12.116995] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:19:12.117050] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:19:12.341693] LOG: [CONN] Frame received (60 bytes): 88 31 c6 15 2b 32 3e 9b 0c 33 cc 6c 82 dc ef 43 ec 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2b e9 24 86 6e 6b ef 55 01 e0 7a 7e cc 05 40 9a 68 cd 0a 2e 27 1f 3b c9 ec -[2026-02-20T18:19:12.341750] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:19:12.341759] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:19:12.341775] LOG: [RX PARSE] RAW Packet (57 bytes): 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC -[2026-02-20T18:19:12.341780] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:19:12.341782] LOG: [RX PARSE] Path length offset: 1, Path length: 43 -[2026-02-20T18:19:12.341795] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=43, firstHop=0x32, lastHop=0xcc, SNR=12.25, RSSI=-58, payload=12 bytes -[2026-02-20T18:19:12.341798] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=43 -[2026-02-20T18:19:12.341800] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:19:12.341804] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:19:12.341818] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:19:12.341821] LOG: [RX FILTER] Raw packet (57 bytes): 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC -[2026-02-20T18:19:12.341825] LOG: [RX FILTER] Header: 0x15 | PathLength: 43 | SNR: 12.25 -[2026-02-20T18:19:12.341829] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:19:12.341832] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:19:12.341835] LOG: [RX FILTER] Channel hash: 0x05 -[2026-02-20T18:19:12.341840] LOG: [RX FILTER] ✓ Channel matched: #bot-tacoma -[2026-02-20T18:19:12.341843] LOG: [RX FILTER] Encrypted message: 9 bytes -[2026-02-20T18:19:12.341845] LOG: [CRYPTO] Decrypting message (9 bytes) -[2026-02-20T18:19:12.341891] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:19:12.341907] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:19:12.341971] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:19:12.341996] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:19:12.342001] LOG: [RX LOG] Dropped packet hex: 15 2B 32 3E 9B 0C 33 CC 6C 82 DC EF 43 EC 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 30 20 75 2B E9 24 86 6E 6B EF 55 01 E0 7A 7E CC 05 40 9A 68 CD 0A 2E 27 1F 3B C9 EC -[2026-02-20T18:19:12.602675] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:12.701936] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:12.701995] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:12.702001] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:13.098660] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:19:17.106227] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.07899, accuracy=3.8m -[2026-02-20T18:19:17.602608] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:17.712996] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:17.713062] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:17.713073] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:22.105470] LOG: [GPS SERVICE] Position stream fired: lat=47.35804, lon=-122.07812, accuracy=3.8m -[2026-02-20T18:19:22.573649] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:19:22.573923] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:19:22.602625] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:22.721835] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:22.721915] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:22.721924] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:27.115507] LOG: [GPS SERVICE] Position stream fired: lat=47.35803, lon=-122.07714, accuracy=3.8m -[2026-02-20T18:19:27.602616] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:19:27.602691] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:27.733502] LOG: [CONN] Frame received (11 bytes): 0c e2 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:19:27.733659] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:19:27.733670] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:19:27.733683] LOG: [CONN] Battery updated: 4066mV (89%) -[2026-02-20T18:19:27.791206] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:27.791267] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:27.791282] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:31.785618] LOG: [GPS SERVICE] Position stream fired: lat=47.35801, lon=-122.07616, accuracy=3.8m -[2026-02-20T18:19:32.583626] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:19:32.583708] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:19:32.583715] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:19:32.583741] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:19:32.583772] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35801, -122.07616 [0.3w]" -[2026-02-20T18:19:32.583779] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:19:32.583783] LOG: [TX LOG] Payload: "@[MapperBot] 47.35801, -122.07616 [0.3w]" -[2026-02-20T18:19:32.583791] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:19:32.583797] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:19:32.583802] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:19:32.583811] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:19:32.583821] LOG: [CONN] Sending ping: @[MapperBot] 47.35801, -122.07616 [0.3w] -[2026-02-20T18:19:32.603505] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:32.651320] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:19:32.651361] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:19:32.651367] LOG: [CONN] Received OK response -[2026-02-20T18:19:32.712543] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 31 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:32.712605] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:32.712616] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:34.334865] LOG: [CONN] Frame received (73 bytes): 88 2f c6 15 01 cc 81 a6 ad 40 99 87 83 01 45 97 c6 95 4b 68 4b 6f 22 4b cf ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 4d e6 5d 25 1e f9 43 9f 65 6f ad 50 d2 c2 b1 35 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:19:34.334954] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:19:34.334972] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:19:34.334998] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:19:34.335006] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:19:34.335010] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:19:34.335024] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=67 bytes -[2026-02-20T18:19:34.335030] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:19:34.335036] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:19:34.335042] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-58 -[2026-02-20T18:19:34.335046] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:19:34.335053] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:19:34.335058] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:19:34.335062] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:19:34.335072] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:19:35.651728] LOG: [PING] Ping sent successfully -[2026-02-20T18:19:36.801670] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07511, accuracy=3.8m -[2026-02-20T18:19:37.573622] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:19:37.573710] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:19:37.584587] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:19:37.602802] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:37.691133] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:37.691189] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:37.691196] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:40.653828] LOG: [PING] RX listening window ended -[2026-02-20T18:19:40.653892] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:19:40.653901] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:19:40.653923] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:19:40.653925] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:19:40.653928] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:19:40.653933] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:19:40.653936] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:19:40.654079] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:19:42.114224] LOG: [GPS SERVICE] Position stream fired: lat=47.35807, lon=-122.07432, accuracy=3.8m -[2026-02-20T18:19:42.602626] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:42.700811] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:42.700861] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:42.700866] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:45.654923] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:19:45.655106] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:19:45.655123] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:19:45.990009] LOG: [CONN] Frame received (82 bytes): 88 2f ce 15 0c cc db 7e 75 20 20 20 75 7e 02 db cc 81 a6 ad 40 99 87 83 01 45 97 c6 95 4b 68 4b 6f 22 4b cf ce c9 20 f6 dd 53 70 8a b5 61 51 4f 4c 7b 0e 08 4d e6 5d 25 1e f9 43 9f 65 6f ad 50 d2 c2 b1 35 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f -[2026-02-20T18:19:45.990100] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:19:45.990118] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:19:45.990153] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F -[2026-02-20T18:19:45.990163] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:19:45.990169] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:19:45.990186] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=11.75, RSSI=-50, payload=65 bytes -[2026-02-20T18:19:45.990195] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:19:45.990199] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:19:45.990205] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:19:45.990213] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:19:45.990244] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:19:45.990249] LOG: [RX FILTER] Raw packet (79 bytes): 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F -[2026-02-20T18:19:45.990259] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 -[2026-02-20T18:19:45.990264] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:19:45.990271] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:19:45.990278] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:19:45.990284] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:19:45.990292] LOG: [RX FILTER] Encrypted message: 62 bytes -[2026-02-20T18:19:45.990299] LOG: [CRYPTO] Decrypting message (62 bytes) -[2026-02-20T18:19:45.990402] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:19:45.990429] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:19:45.990636] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:19:45.990765] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:19:45.990774] LOG: [RX LOG] Dropped packet hex: 15 0C CC DB 7E 75 20 20 20 75 7E 02 DB CC 81 A6 AD 40 99 87 83 01 45 97 C6 95 4B 68 4B 6F 22 4B CF CE C9 20 F6 DD 53 70 8A B5 61 51 4F 4C 7B 0E 08 4D E6 5D 25 1E F9 43 9F 65 6F AD 50 D2 C2 B1 35 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F -[2026-02-20T18:19:46.179928] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:19:46.179964] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:19:46.179969] LOG: [API] Response (200) in 0.52s: {"success":true,"expires_at":1771640685} -[2026-02-20T18:19:46.179977] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:19:46.179984] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:19:46.180194] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:19:46.180201] LOG: [APP] Upload success: +1 items (total: 64) -[2026-02-20T18:19:46.803150] LOG: [GPS SERVICE] Position stream fired: lat=47.35809, lon=-122.07409, accuracy=4.2m -[2026-02-20T18:19:46.803196] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:19:46.803263] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:19:47.602762] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:47.712575] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:47.712702] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:47.712726] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:51.180737] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:19:52.124801] LOG: [GPS SERVICE] Position stream fired: lat=47.35835, lon=-122.07397, accuracy=24.5m -[2026-02-20T18:19:52.573964] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:19:52.574187] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:19:52.604997] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:52.723912] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:52.724011] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:52.724022] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:19:57.107416] LOG: [GPS SERVICE] Position stream fired: lat=47.35887, lon=-122.07400, accuracy=4.4m -[2026-02-20T18:19:57.603656] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:19:57.603907] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:19:57.733769] LOG: [CONN] Frame received (11 bytes): 0c db 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:19:57.733920] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:19:57.733938] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:19:57.733964] LOG: [CONN] Battery updated: 4059mV (88%) -[2026-02-20T18:19:57.792915] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:19:57.793043] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:19:57.793064] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:01.777177] LOG: [GPS SERVICE] Position stream fired: lat=47.35938, lon=-122.07402, accuracy=4.2m -[2026-02-20T18:20:02.602803] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:02.654509] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ce 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:20:02.654731] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:02.654748] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:05.447963] LOG: [CONN] Frame received (44 bytes): 88 2f c6 15 04 15 ae 7e cc 11 9d cb 1f fd e7 3c ac 9e 97 81 b4 42 c3 a2 29 8f d1 e3 b5 d7 30 69 2d 6b 4b 26 8d 3d 7d a9 56 22 87 9b -[2026-02-20T18:20:05.448023] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:05.448034] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:05.448050] LOG: [RX PARSE] RAW Packet (41 bytes): 15 04 15 AE 7E CC 11 9D CB 1F FD E7 3C AC 9E 97 81 B4 42 C3 A2 29 8F D1 E3 B5 D7 30 69 2D 6B 4B 26 8D 3D 7D A9 56 22 87 9B -[2026-02-20T18:20:05.448054] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:05.448057] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:20:05.448069] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0x15, lastHop=0xcc, SNR=11.75, RSSI=-58, payload=35 bytes -[2026-02-20T18:20:05.448073] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:20:05.448079] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:05.448081] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:05.448093] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:05.448098] LOG: [RX FILTER] Raw packet (41 bytes): 15 04 15 AE 7E CC 11 9D CB 1F FD E7 3C AC 9E 97 81 B4 42 C3 A2 29 8F D1 E3 B5 D7 30 69 2D 6B 4B 26 8D 3D 7D A9 56 22 87 9B -[2026-02-20T18:20:05.448103] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 11.75 -[2026-02-20T18:20:05.448109] LOG: [RX FILTER] ✓ RSSI OK (-58 < -30) -[2026-02-20T18:20:05.448112] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:05.448115] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:20:05.448120] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:20:05.448124] LOG: [RX FILTER] Encrypted message: 32 bytes -[2026-02-20T18:20:05.448127] LOG: [CRYPTO] Decrypting message (32 bytes) -[2026-02-20T18:20:05.448150] LOG: [CRYPTO] Decrypted successfully (32 bytes) -[2026-02-20T18:20:05.448213] LOG: [RX FILTER] Decrypted message (13 chars): "hankest: Test" -[2026-02-20T18:20:05.448223] LOG: [RX FILTER] Printable ratio: 100.0% (threshold: 60.0%) -[2026-02-20T18:20:05.448225] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:20:05.448236] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.75, path_length=4 -[2026-02-20T18:20:05.448238] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:20:05.448246] LOG: [RX BATCH] First observation for repeater CC: SNR=11.75 -[2026-02-20T18:20:05.448252] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:20:05.448259] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:20:05.448267] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.75, location=47.35938,-122.07402 -[2026-02-20T18:20:05.448273] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:20:05.448281] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.35938,-122.07402 (batch tracking: 1 repeaters, rxCount: 33) -[2026-02-20T18:20:05.448294] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:20:05.448302] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.75, location=47.35938,-122.07402 -[2026-02-20T18:20:05.448428] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:20:05.448434] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:20:05.448438] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:20:06.789128] LOG: [GPS SERVICE] Position stream fired: lat=47.35997, lon=-122.07414, accuracy=4.9m -[2026-02-20T18:20:06.789182] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:20:06.789193] LOG: [RX BATCH] Distance check for repeater CC: 65.44m from first observation (threshold=25m) -[2026-02-20T18:20:06.789198] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:20:06.789202] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:20:06.789208] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:20:06.789217] LOG: [RX BATCH] Posting repeater CC: snr=11.75, location=47.35938,-122.07402 -[2026-02-20T18:20:06.789220] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:20:06.789225] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.75, location=47.35938,-122.07402 -[2026-02-20T18:20:06.789233] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.75 <= pin 11.75 -[2026-02-20T18:20:06.789238] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:20:06.789245] LOG: [APP] Added RX log entry: repeater=CC, snr=11.75, pathLen=4 -[2026-02-20T18:20:06.789303] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:20:06.789307] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:20:07.576403] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:20:07.576506] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:20:07.576525] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:20:07.577135] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:20:07.602631] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:07.752358] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c6 2f 10 00 00 00 97 23 00 00 -[2026-02-20T18:20:07.752411] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:07.752417] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:08.163554] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:20:08.163580] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:20:08.163586] LOG: [API] Response (200) in 0.59s: {"success":true,"expires_at":1771640707} -[2026-02-20T18:20:08.163591] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:20:08.163598] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:20:08.163705] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:20:08.163711] LOG: [APP] Upload success: +1 items (total: 65) -[2026-02-20T18:20:10.656646] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:20:10.656725] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:20:10.656731] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:20:10.656748] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:20:10.656766] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.35997, -122.07414 [0.3w]" -[2026-02-20T18:20:10.656770] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:20:10.656774] LOG: [TX LOG] Payload: "@[MapperBot] 47.35997, -122.07414 [0.3w]" -[2026-02-20T18:20:10.656778] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:20:10.656782] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:20:10.656789] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:20:10.656791] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:20:10.656799] LOG: [CONN] Sending ping: @[MapperBot] 47.35997, -122.07414 [0.3w] -[2026-02-20T18:20:10.840806] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:20:10.840869] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:20:10.840873] LOG: [CONN] Received OK response -[2026-02-20T18:20:11.799900] LOG: [GPS SERVICE] Position stream fired: lat=47.36040, lon=-122.07456, accuracy=4.1m -[2026-02-20T18:20:12.137792] LOG: [CONN] Frame received (73 bytes): 88 32 c7 15 01 cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:20:12.137869] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:12.137884] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:12.137904] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:20:12.137909] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:12.137912] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:20:12.137928] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.5, RSSI=-57, payload=67 bytes -[2026-02-20T18:20:12.137932] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:20:12.137937] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:20:12.137940] LOG: [TX LOG] Processing rx_log entry: SNR=12.5, RSSI=-57 -[2026-02-20T18:20:12.137943] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:20:12.137948] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:20:12.137951] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:12.137955] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:12.137960] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:20:12.603632] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:12.795943] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 -[2026-02-20T18:20:12.796076] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:12.796098] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:13.164748] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:20:13.812311] LOG: [PING] Ping sent successfully -[2026-02-20T18:20:15.658486] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:20:17.118678] LOG: [GPS SERVICE] Position stream fired: lat=47.36073, lon=-122.07520, accuracy=3.8m -[2026-02-20T18:20:17.118725] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:20:17.118806] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:20:17.606006] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:17.656581] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 -[2026-02-20T18:20:17.656705] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:17.656724] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:18.812966] LOG: [PING] RX listening window ended -[2026-02-20T18:20:18.813123] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:20:18.813165] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:20:18.813265] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:20:18.813280] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:20:18.813292] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:20:18.813323] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:20:18.813340] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:20:18.813789] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:20:21.786129] LOG: [GPS SERVICE] Position stream fired: lat=47.36110, lon=-122.07562, accuracy=3.8m -[2026-02-20T18:20:22.574744] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:20:22.574972] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:20:22.574993] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:20:22.603033] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:22.664535] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 32 10 00 00 00 98 23 00 00 -[2026-02-20T18:20:22.664611] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:22.664623] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:22.726391] LOG: [CONN] Frame received (83 bytes): 88 2e bb 15 0c cc db 6c 24 c5 75 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d -[2026-02-20T18:20:22.726692] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:22.726718] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:22.726767] LOG: [RX PARSE] RAW Packet (80 bytes): 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:20:22.726777] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:22.726787] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:20:22.726806] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xcc, lastHop=0xcc, SNR=11.5, RSSI=-69, payload=66 bytes -[2026-02-20T18:20:22.726818] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:20:22.726824] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:22.726830] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:22.726841] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:20:22.726885] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:22.726891] LOG: [RX FILTER] Raw packet (80 bytes): 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:20:22.726907] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.5 -[2026-02-20T18:20:22.726912] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:20:22.726922] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:22.726930] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:20:22.726937] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:20:22.726948] LOG: [RX FILTER] Encrypted message: 63 bytes -[2026-02-20T18:20:22.726955] LOG: [CRYPTO] Decrypting message (63 bytes) -[2026-02-20T18:20:22.727077] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:22.727120] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:22.727272] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:20:22.727347] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:20:22.727354] LOG: [RX LOG] Dropped packet hex: 15 0C CC DB 6C 24 C5 75 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D -[2026-02-20T18:20:23.224661] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:20:23.224728] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:20:23.224746] LOG: [API] Response (200) in 0.65s: {"success":true,"expires_at":1771640722} -[2026-02-20T18:20:23.224759] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:20:23.224777] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:20:23.225199] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:20:23.225220] LOG: [APP] Upload success: +1 items (total: 66) -[2026-02-20T18:20:23.815160] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:20:23.815332] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:20:26.781699] LOG: [GPS SERVICE] Position stream fired: lat=47.36157, lon=-122.07578, accuracy=3.8m -[2026-02-20T18:20:26.804844] LOG: [CONN] Frame received (83 bytes): 88 2d c4 15 12 cc db 6c 24 c5 75 20 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 -[2026-02-20T18:20:26.804920] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:26.804939] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:26.804978] LOG: [RX PARSE] RAW Packet (80 bytes): 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 -[2026-02-20T18:20:26.804989] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:26.804995] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:20:26.805009] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=18, firstHop=0xcc, lastHop=0xcc, SNR=11.25, RSSI=-60, payload=60 bytes -[2026-02-20T18:20:26.805019] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=18 -[2026-02-20T18:20:26.805025] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:26.805033] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:26.805039] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:20:26.805079] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:26.805086] LOG: [RX FILTER] Raw packet (80 bytes): 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 -[2026-02-20T18:20:26.805099] LOG: [RX FILTER] Header: 0x15 | PathLength: 18 | SNR: 11.25 -[2026-02-20T18:20:26.805104] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:20:26.805112] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:26.805117] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:20:26.805123] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:20:26.805131] LOG: [RX FILTER] Encrypted message: 57 bytes -[2026-02-20T18:20:26.805137] LOG: [CRYPTO] Decrypting message (57 bytes) -[2026-02-20T18:20:26.805237] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:26.805262] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:26.805378] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:20:26.805440] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:20:26.805446] LOG: [RX LOG] Dropped packet hex: 15 12 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 -[2026-02-20T18:20:27.602788] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:20:27.602980] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:27.793028] LOG: [CONN] Frame received (11 bytes): 0c e5 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:20:27.793158] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:20:27.793172] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:20:27.793183] LOG: [CONN] Battery updated: 4069mV (89%) -[2026-02-20T18:20:27.853440] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff 81 d4 10 00 00 00 98 23 00 00 -[2026-02-20T18:20:27.853578] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:27.853597] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:20:28.225667] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:20:29.283362] LOG: [CONN] Frame received (83 bytes): 88 31 c7 15 11 cc db 6c 24 c5 75 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 94 25 e0 39 e7 92 a9 03 -[2026-02-20T18:20:29.283542] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:29.283573] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:29.283657] LOG: [RX PARSE] RAW Packet (80 bytes): 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 -[2026-02-20T18:20:29.283674] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:29.283690] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T18:20:29.283761] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-57, payload=61 bytes -[2026-02-20T18:20:29.283775] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T18:20:29.283802] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:29.283811] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:29.283823] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:20:29.283900] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:29.283912] LOG: [RX FILTER] Raw packet (80 bytes): 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 -[2026-02-20T18:20:29.283935] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 12.25 -[2026-02-20T18:20:29.283946] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:20:29.283957] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:29.283972] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:20:29.283985] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:20:29.283997] LOG: [RX FILTER] Encrypted message: 58 bytes -[2026-02-20T18:20:29.284012] LOG: [CRYPTO] Decrypting message (58 bytes) -[2026-02-20T18:20:29.284193] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:29.284246] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:29.284479] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:20:29.284632] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:20:29.284644] LOG: [RX LOG] Dropped packet hex: 15 11 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 94 25 E0 39 E7 92 A9 03 -[2026-02-20T18:20:31.738325] LOG: [CONN] Frame received (83 bytes): 88 34 c7 15 19 cc db 6c 24 c5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7e db cc 81 5a 3b 8f 21 d7 84 b1 6f c2 de 7f a7 05 32 1b 46 a3 41 d6 f7 e1 d7 77 9e 03 d3 38 32 f4 f7 f8 80 62 0a c2 19 34 c3 cd da 40 41 20 ac b2 c3 75 c8 07 08 19 55 -[2026-02-20T18:20:31.738349] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:31.738366] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:31.738387] LOG: [RX PARSE] RAW Packet (80 bytes): 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 -[2026-02-20T18:20:31.738396] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:31.738401] LOG: [RX PARSE] Path length offset: 1, Path length: 25 -[2026-02-20T18:20:31.738412] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=25, firstHop=0xcc, lastHop=0xcc, SNR=13.0, RSSI=-57, payload=53 bytes -[2026-02-20T18:20:31.738418] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=25 -[2026-02-20T18:20:31.738420] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:31.738423] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:31.738429] LOG: [RX LOG] CARpeater pass-through: stripped CC, reporting underlying repeater DB -[2026-02-20T18:20:31.738449] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:31.738452] LOG: [RX FILTER] Raw packet (80 bytes): 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 -[2026-02-20T18:20:31.738459] LOG: [RX FILTER] Header: 0x15 | PathLength: 25 | SNR: 13.0 -[2026-02-20T18:20:31.738462] LOG: [RX FILTER] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:20:31.738466] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:31.738471] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:20:31.738475] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:20:31.738480] LOG: [RX FILTER] Encrypted message: 50 bytes -[2026-02-20T18:20:31.738484] LOG: [CRYPTO] Decrypting message (50 bytes) -[2026-02-20T18:20:31.738581] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:31.738638] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:20:31.738717] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:20:31.738755] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:20:31.738758] LOG: [RX LOG] Dropped packet hex: 15 19 CC DB 6C 24 C5 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 75 7E DB CC 81 5A 3B 8F 21 D7 84 B1 6F C2 DE 7F A7 05 32 1B 46 A3 41 D6 F7 E1 D7 77 9E 03 D3 38 32 F4 F7 F8 80 62 0A C2 19 34 C3 CD DA 40 41 20 AC B2 C3 75 C8 07 08 19 55 -[2026-02-20T18:20:31.789432] LOG: [GPS SERVICE] Position stream fired: lat=47.36194, lon=-122.07583, accuracy=4.2m -[2026-02-20T18:20:32.602929] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:32.683251] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 -[2026-02-20T18:20:32.683382] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:32.683402] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:36.782466] LOG: [GPS SERVICE] Position stream fired: lat=47.36211, lon=-122.07588, accuracy=4.0m -[2026-02-20T18:20:37.573806] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:20:37.573979] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:20:37.605467] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:37.693364] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 -[2026-02-20T18:20:37.693502] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:37.693528] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:41.795619] LOG: [GPS SERVICE] Position stream fired: lat=47.36248, lon=-122.07627, accuracy=4.1m -[2026-02-20T18:20:42.603046] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:42.703857] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 -[2026-02-20T18:20:42.704004] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:42.704026] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:46.786512] LOG: [GPS SERVICE] Position stream fired: lat=47.36286, lon=-122.07671, accuracy=4.0m -[2026-02-20T18:20:47.603085] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:47.713741] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 34 10 00 00 00 99 23 00 00 -[2026-02-20T18:20:47.713891] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:47.713914] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:48.825060] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:20:48.825223] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:20:48.825252] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:20:48.825296] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:20:48.825346] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36286, -122.07671 [0.3w]" -[2026-02-20T18:20:48.825358] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:20:48.825367] LOG: [TX LOG] Payload: "@[MapperBot] 47.36286, -122.07671 [0.3w]" -[2026-02-20T18:20:48.825386] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:20:48.825399] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:20:48.825416] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:20:48.825428] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:20:48.825449] LOG: [CONN] Sending ping: @[MapperBot] 47.36286, -122.07671 [0.3w] -[2026-02-20T18:20:48.975177] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:20:48.975305] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:20:48.975333] LOG: [CONN] Received OK response -[2026-02-20T18:20:49.818766] LOG: [CONN] Frame received (73 bytes): 88 2b b7 15 01 cc 81 20 2c cd da 5b 0f a1 8f ef 4d 83 92 cd 75 db de e1 7f 44 96 6d c4 a7 68 a6 1d 8f 43 53 aa 5d 04 43 8b 87 b4 82 33 11 57 1b 8f e5 23 d7 33 4f a0 9b 08 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:20:49.818913] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:49.818943] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:49.819016] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 20 2C CD DA 5B 0F A1 8F EF 4D 83 92 CD 75 DB DE E1 7F 44 96 6D C4 A7 68 A6 1D 8F 43 53 AA 5D 04 43 8B 87 B4 82 33 11 57 1B 8F E5 23 D7 33 4F A0 9B 08 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:20:49.819039] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:49.819050] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:20:49.819085] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=10.75, RSSI=-73, payload=67 bytes -[2026-02-20T18:20:49.819101] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:20:49.819111] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:20:49.819136] LOG: [TX LOG] Processing rx_log entry: SNR=10.75, RSSI=-73 -[2026-02-20T18:20:49.819147] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:20:49.819156] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:20:49.819173] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:49.819183] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:49.819193] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:20:51.802167] LOG: [GPS SERVICE] Position stream fired: lat=47.36333, lon=-122.07693, accuracy=4.0m -[2026-02-20T18:20:51.802213] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:20:51.802278] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:20:51.980132] LOG: [PING] Ping sent successfully -[2026-02-20T18:20:52.573664] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:20:52.573777] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:20:52.602748] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:52.722887] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff b7 2b 11 00 00 00 99 23 00 00 -[2026-02-20T18:20:52.723018] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:52.723037] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:20:53.826732] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:20:56.980668] LOG: [PING] RX listening window ended -[2026-02-20T18:20:56.980713] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:20:56.980734] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:20:56.980766] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:20:56.980772] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:20:56.980779] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:20:56.980792] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:20:56.980798] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:20:56.981333] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:20:57.114277] LOG: [GPS SERVICE] Position stream fired: lat=47.36382, lon=-122.07693, accuracy=3.8m -[2026-02-20T18:20:57.604893] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:20:57.605092] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:20:57.763813] LOG: [CONN] Frame received (11 bytes): 0c d7 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:20:57.763905] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:20:57.763916] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:20:57.763928] LOG: [CONN] Battery updated: 4055mV (88%) -[2026-02-20T18:20:57.796097] LOG: [CONN] Frame received (82 bytes): 88 31 c2 15 0a 08 26 f8 6a 9a aa cd 7a 7e cc 11 a3 b9 84 a9 75 a7 52 54 7a 6a 9b 16 7f 20 e2 d2 6a d6 01 9c a6 3c 42 62 0d 26 25 87 bc c0 e7 74 64 02 b8 7c ad b3 71 84 7b a8 04 24 76 28 58 1a 5e f1 7b 4c 97 d2 14 00 21 92 e5 fa e3 4c 80 bd 25 22 -[2026-02-20T18:20:57.796199] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:20:57.796224] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:20:57.796282] LOG: [RX PARSE] RAW Packet (79 bytes): 15 0A 08 26 F8 6A 9A AA CD 7A 7E CC 11 A3 B9 84 A9 75 A7 52 54 7A 6A 9B 16 7F 20 E2 D2 6A D6 01 9C A6 3C 42 62 0D 26 25 87 BC C0 E7 74 64 02 B8 7C AD B3 71 84 7B A8 04 24 76 28 58 1A 5E F1 7B 4C 97 D2 14 00 21 92 E5 FA E3 4C 80 BD 25 22 -[2026-02-20T18:20:57.796299] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:20:57.796307] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:20:57.796329] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0x08, lastHop=0xcc, SNR=12.25, RSSI=-62, payload=67 bytes -[2026-02-20T18:20:57.796341] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:20:57.796349] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:20:57.796366] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:20:57.796421] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:20:57.796430] LOG: [RX FILTER] Raw packet (79 bytes): 15 0A 08 26 F8 6A 9A AA CD 7A 7E CC 11 A3 B9 84 A9 75 A7 52 54 7A 6A 9B 16 7F 20 E2 D2 6A D6 01 9C A6 3C 42 62 0D 26 25 87 BC C0 E7 74 64 02 B8 7C AD B3 71 84 7B A8 04 24 76 28 58 1A 5E F1 7B 4C 97 D2 14 00 21 92 E5 FA E3 4C 80 BD 25 22 -[2026-02-20T18:20:57.796447] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 -[2026-02-20T18:20:57.796456] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:20:57.796462] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:20:57.796473] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:20:57.796481] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:20:57.796488] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:20:57.796500] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:20:57.796559] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:20:57.796684] LOG: [RX FILTER] Decrypted message (45 chars): "Dude: @[hankest] heard 7 hops on bellingham" -[2026-02-20T18:20:57.796701] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) -[2026-02-20T18:20:57.796713] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:20:57.796734] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=10 -[2026-02-20T18:20:57.796749] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:20:57.796760] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:20:57.796778] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:20:57.796796] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:20:57.796811] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36382,-122.07693 -[2026-02-20T18:20:57.796828] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:20:57.796844] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36382,-122.07693 (batch tracking: 1 repeaters, rxCount: 34) -[2026-02-20T18:20:57.796863] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:20:57.796878] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36382,-122.07693 -[2026-02-20T18:20:57.797229] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:20:57.797239] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:20:57.797247] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:20:57.798140] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 31 11 00 00 00 9a 23 00 00 -[2026-02-20T18:20:57.798155] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:20:57.798167] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:01.783836] LOG: [GPS SERVICE] Position stream fired: lat=47.36427, lon=-122.07690, accuracy=3.9m -[2026-02-20T18:21:01.783897] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:21:01.783909] LOG: [RX BATCH] Distance check for repeater CC: 49.88m from first observation (threshold=25m) -[2026-02-20T18:21:01.783913] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:21:01.783918] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:21:01.783925] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:21:01.783933] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36382,-122.07693 -[2026-02-20T18:21:01.783938] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:01.783943] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36382,-122.07693 -[2026-02-20T18:21:01.783953] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:21:01.783958] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:21:01.783965] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=10 -[2026-02-20T18:21:01.784043] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:21:01.784048] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:21:01.981588] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:21:01.981687] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:21:01.981694] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:21:01.981699] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:21:01.982038] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:21:02.433578] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:21:02.433670] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:21:02.433688] LOG: [API] Response (200) in 0.45s: {"success":true,"expires_at":1771640762} -[2026-02-20T18:21:02.433713] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:21:02.433731] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:21:02.434506] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:21:02.434556] LOG: [APP] Upload success: +2 items (total: 68) -[2026-02-20T18:21:02.602855] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:02.711143] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 31 11 00 00 00 9a 23 00 00 -[2026-02-20T18:21:02.711214] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:02.711223] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:05.999469] LOG: [CONN] Frame received (144 bytes): 88 30 be 15 0e 01 e0 7e 75 20 20 20 20 20 20 20 53 7e cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 29 e0 dd c8 -[2026-02-20T18:21:05.999542] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:05.999557] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:05.999597] LOG: [RX PARSE] RAW Packet (141 bytes): 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 -[2026-02-20T18:21:05.999607] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:05.999613] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:21:05.999627] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0x01, lastHop=0xcc, SNR=12.0, RSSI=-66, payload=125 bytes -[2026-02-20T18:21:05.999634] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:21:05.999640] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:05.999643] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:05.999687] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:05.999691] LOG: [RX FILTER] Raw packet (141 bytes): 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 -[2026-02-20T18:21:05.999700] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.0 -[2026-02-20T18:21:05.999705] LOG: [RX FILTER] ✓ RSSI OK (-66 < -30) -[2026-02-20T18:21:05.999711] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:05.999714] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:21:05.999718] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:21:05.999725] LOG: [RX FILTER] Encrypted message: 122 bytes -[2026-02-20T18:21:05.999729] LOG: [CRYPTO] Decrypting message (122 bytes) -[2026-02-20T18:21:05.999873] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:05.999895] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:05.999995] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:06.000052] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:06.000059] LOG: [RX LOG] Dropped packet hex: 15 0E 01 E0 7E 75 20 20 20 20 20 20 20 53 7E CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD C8 -[2026-02-20T18:21:06.795053] LOG: [GPS SERVICE] Position stream fired: lat=47.36459, lon=-122.07667, accuracy=3.8m -[2026-02-20T18:21:07.435724] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:21:07.574113] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:21:07.574222] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:21:07.603007] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:07.693634] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff be 30 11 00 00 00 9a 23 00 00 -[2026-02-20T18:21:07.693766] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:07.693785] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:11.788957] LOG: [GPS SERVICE] Position stream fired: lat=47.36479, lon=-122.07607, accuracy=3.8m -[2026-02-20T18:21:12.602800] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:12.704006] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff 89 fc 11 00 00 00 9a 23 00 00 -[2026-02-20T18:21:12.704110] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:12.704123] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:21:13.749543] LOG: [CONN] Frame received (146 bytes): 88 2f c8 15 11 01 e0 7e 75 20 20 20 20 20 20 20 20 53 7e ef db cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 29 e0 dd -[2026-02-20T18:21:13.749676] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:13.749704] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:13.749792] LOG: [RX PARSE] RAW Packet (143 bytes): 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD -[2026-02-20T18:21:13.749818] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:13.749831] LOG: [RX PARSE] Path length offset: 1, Path length: 17 -[2026-02-20T18:21:13.749858] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=17, firstHop=0x01, lastHop=0xcc, SNR=11.75, RSSI=-56, payload=124 bytes -[2026-02-20T18:21:13.749872] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=17 -[2026-02-20T18:21:13.749881] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:13.749889] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:13.749980] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:13.749989] LOG: [RX FILTER] Raw packet (143 bytes): 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD -[2026-02-20T18:21:13.750008] LOG: [RX FILTER] Header: 0x15 | PathLength: 17 | SNR: 11.75 -[2026-02-20T18:21:13.750020] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:21:13.750033] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:13.750042] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:21:13.750052] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:21:13.750071] LOG: [RX FILTER] Encrypted message: 121 bytes -[2026-02-20T18:21:13.750079] LOG: [CRYPTO] Decrypting message (121 bytes) -[2026-02-20T18:21:13.750268] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:13.750309] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:13.750507] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:13.750714] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:13.750720] LOG: [RX LOG] Dropped packet hex: 15 11 01 E0 7E 75 20 20 20 20 20 20 20 20 53 7E EF DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 29 E0 DD -[2026-02-20T18:21:16.009994] LOG: [GPS SERVICE] Position stream fired: lat=47.36505, lon=-122.07545, accuracy=3.8m -[2026-02-20T18:21:16.339458] LOG: [CONN] Frame received (148 bytes): 88 f8 87 15 15 01 e0 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e db ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 e0 -[2026-02-20T18:21:16.339502] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:16.339534] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:16.339606] LOG: [RX PARSE] RAW Packet (145 bytes): 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:16.339627] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:16.339638] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:21:16.339661] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0x01, lastHop=0xdb, SNR=-2.0, RSSI=-121, payload=122 bytes -[2026-02-20T18:21:16.339673] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:21:16.339680] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:16.339685] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:16.339760] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:16.339768] LOG: [RX FILTER] Raw packet (145 bytes): 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:16.339787] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: -2.0 -[2026-02-20T18:21:16.339799] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) -[2026-02-20T18:21:16.339807] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:16.339813] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:21:16.339822] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:21:16.339830] LOG: [RX FILTER] Encrypted message: 119 bytes -[2026-02-20T18:21:16.339837] LOG: [CRYPTO] Decrypting message (119 bytes) -[2026-02-20T18:21:16.339985] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:16.340100] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:16.340258] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:16.340357] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:16.340368] LOG: [RX LOG] Dropped packet hex: 15 15 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:17.603810] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:17.741045] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 87 f8 11 00 00 00 9b 23 00 00 -[2026-02-20T18:21:17.741114] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:17.741121] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:19.593134] LOG: [CONN] Frame received (149 bytes): 88 31 c5 15 16 01 e0 7e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7e db cc ca a3 7e 3f 3b 6a 62 91 83 19 cf d5 be d4 7f 7f 6b a6 fa 35 47 8a 0e bf c2 99 ab 60 fe c8 db 23 1f f2 99 aa 59 c4 36 44 1b cc 68 81 f1 ac 74 b3 e3 37 7e 7a 25 41 bb 0c 31 8c f2 8b 2e f7 af 41 44 6b 68 bc 46 81 9e 78 be e2 38 85 78 2c 16 8b 19 ca 52 76 05 37 f3 a6 6a cc c4 47 64 3e e2 ea a3 b3 e7 58 34 18 a3 3f 53 eb b2 62 cb d2 f6 40 63 1b 26 59 a1 0c 1e be 08 e0 -[2026-02-20T18:21:19.593300] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:19.593329] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:19.593456] LOG: [RX PARSE] RAW Packet (146 bytes): 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:19.593491] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:19.593503] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T18:21:19.593532] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0x01, lastHop=0xcc, SNR=12.25, RSSI=-59, payload=122 bytes -[2026-02-20T18:21:19.593551] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T18:21:19.593561] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:19.593574] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:19.593692] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:19.593704] LOG: [RX FILTER] Raw packet (146 bytes): 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:19.593733] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 12.25 -[2026-02-20T18:21:19.593751] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:21:19.593762] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:19.593772] LOG: [RX FILTER] Channel hash: 0xca -[2026-02-20T18:21:19.593789] LOG: [RX FILTER] ✓ Channel matched: #bot -[2026-02-20T18:21:19.593800] LOG: [RX FILTER] Encrypted message: 119 bytes -[2026-02-20T18:21:19.593815] LOG: [CRYPTO] Decrypting message (119 bytes) -[2026-02-20T18:21:19.594028] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:19.594084] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:19.594299] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:19.594474] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:19.594490] LOG: [RX LOG] Dropped packet hex: 15 16 01 E0 7E 75 20 20 20 20 20 20 20 20 20 20 20 20 20 20 53 7E DB CC CA A3 7E 3F 3B 6A 62 91 83 19 CF D5 BE D4 7F 7F 6B A6 FA 35 47 8A 0E BF C2 99 AB 60 FE C8 DB 23 1F F2 99 AA 59 C4 36 44 1B CC 68 81 F1 AC 74 B3 E3 37 7E 7A 25 41 BB 0C 31 8C F2 8B 2E F7 AF 41 44 6B 68 BC 46 81 9E 78 BE E2 38 85 78 2C 16 8B 19 CA 52 76 05 37 F3 A6 6A CC C4 47 64 3E E2 EA A3 B3 E7 58 34 18 A3 3F 53 EB B2 62 CB D2 F6 40 63 1B 26 59 A1 0C 1E BE 08 E0 -[2026-02-20T18:21:22.573819] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:21:22.573941] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:21:22.605415] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:22.783450] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 31 11 00 00 00 9b 23 00 00 -[2026-02-20T18:21:22.783592] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:22.783617] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:23.010322] LOG: [GPS SERVICE] Position stream fired: lat=47.36569, lon=-122.07524, accuracy=3.8m -[2026-02-20T18:21:23.010421] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:21:23.010448] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:21:23.191410] LOG: [CONN] Frame received (101 bytes): 88 f3 87 15 0d c7 32 75 62 54 1e 29 1f 5a 15 e0 86 db 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 56 -[2026-02-20T18:21:23.191516] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:23.191534] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:23.191582] LOG: [RX PARSE] RAW Packet (98 bytes): 15 0D C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 -[2026-02-20T18:21:23.191594] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:23.191599] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:21:23.191620] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xc7, lastHop=0xdb, SNR=-3.25, RSSI=-121, payload=83 bytes -[2026-02-20T18:21:23.191626] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:21:23.191631] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:23.191638] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:23.191682] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:23.191689] LOG: [RX FILTER] Raw packet (98 bytes): 15 0D C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 -[2026-02-20T18:21:23.191700] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: -3.25 -[2026-02-20T18:21:23.191710] LOG: [RX FILTER] ✓ RSSI OK (-121 < -30) -[2026-02-20T18:21:23.191714] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:23.191719] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:23.191727] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:23.191734] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:23.191739] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:23.191797] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:23.191922] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34248, -122.52344 [..." -[2026-02-20T18:21:23.191935] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:23.191939] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:23.191958] LOG: [RX LOG] Packet heard via last hop: DB, SNR=-3.25, path_length=13 -[2026-02-20T18:21:23.191966] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:23.191976] LOG: [RX BATCH] First observation for repeater DB: SNR=-3.25 -[2026-02-20T18:21:23.191986] LOG: [RX BATCH] Started 30s timeout timer for repeater DB -[2026-02-20T18:21:23.192002] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:23.192013] LOG: [APP] Immediate RX observation: repeater=DB, snr=-3.25, location=47.36569,-122.07524 -[2026-02-20T18:21:23.192026] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:21:23.192037] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36569,-122.07524 (batch tracking: 1 repeaters, rxCount: 35) -[2026-02-20T18:21:23.192050] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:23.192060] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=-3.25, location=47.36569,-122.07524 -[2026-02-20T18:21:23.192271] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:21:23.192277] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:21:23.192281] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:21:24.620233] LOG: [CONN] Frame received (102 bytes): 88 31 c0 15 0e c7 32 75 62 54 1e 29 1f 5a 15 e0 86 db cc 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 56 -[2026-02-20T18:21:24.620365] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:24.620389] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:24.620449] LOG: [RX PARSE] RAW Packet (99 bytes): 15 0E C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 -[2026-02-20T18:21:24.620463] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:24.620475] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:21:24.620492] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xc7, lastHop=0xcc, SNR=12.25, RSSI=-64, payload=83 bytes -[2026-02-20T18:21:24.620505] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:21:24.620514] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:24.620520] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:24.620578] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:24.620586] LOG: [RX FILTER] Raw packet (99 bytes): 15 0E C7 32 75 62 54 1E 29 1F 5A 15 E0 86 DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 56 -[2026-02-20T18:21:24.620602] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.25 -[2026-02-20T18:21:24.620611] LOG: [RX FILTER] ✓ RSSI OK (-64 < -30) -[2026-02-20T18:21:24.620622] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:24.620631] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:24.620638] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:24.620649] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:24.620657] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:24.620728] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:24.620860] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34248, -122.52344 [..." -[2026-02-20T18:21:24.620881] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:24.620887] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:24.620911] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.25, path_length=14 -[2026-02-20T18:21:24.620917] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:24.620932] LOG: [RX BATCH] First observation for repeater CC: SNR=12.25 -[2026-02-20T18:21:24.620944] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:21:24.620959] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:24.620977] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.25, location=47.36569,-122.07524 -[2026-02-20T18:21:24.620989] LOG: [APP] Current batch tracking: 1 repeaters: {DB} -[2026-02-20T18:21:24.621007] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36569,-122.07524 (batch tracking: 2 repeaters, rxCount: 36) -[2026-02-20T18:21:24.621022] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:24.621039] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.25, location=47.36569,-122.07524 -[2026-02-20T18:21:26.042733] LOG: [CONN] Frame received (108 bytes): 88 04 8b 15 15 c7 32 75 62 54 1e 29 1f 5a 15 e0 53 e3 07 7e 75 20 20 53 7a db 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 -[2026-02-20T18:21:26.042844] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:26.042870] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:26.042945] LOG: [RX PARSE] RAW Packet (105 bytes): 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:26.042964] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:26.042975] LOG: [RX PARSE] Path length offset: 1, Path length: 21 -[2026-02-20T18:21:26.043] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=21, firstHop=0xc7, lastHop=0xdb, SNR=1.0, RSSI=-117, payload=82 bytes -[2026-02-20T18:21:26.043011] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=21 -[2026-02-20T18:21:26.043024] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:26.043033] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:26.043101] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:26.043110] LOG: [RX FILTER] Raw packet (105 bytes): 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:26.043128] LOG: [RX FILTER] Header: 0x15 | PathLength: 21 | SNR: 1.0 -[2026-02-20T18:21:26.043139] LOG: [RX FILTER] ✓ RSSI OK (-117 < -30) -[2026-02-20T18:21:26.043151] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:26.043160] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:26.043169] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:26.043181] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:21:26.043190] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:21:26.043329] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:26.043365] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:26.043522] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:26.043631] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:26.043641] LOG: [RX LOG] Dropped packet hex: 15 15 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:26.983430] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:21:26.983511] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:21:26.983528] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:21:26.983579] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:21:26.983625] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36569, -122.07524 [0.3w]" -[2026-02-20T18:21:26.983641] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:21:26.983651] LOG: [TX LOG] Payload: "@[MapperBot] 47.36569, -122.07524 [0.3w]" -[2026-02-20T18:21:26.983664] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:21:26.983683] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:21:26.983695] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:21:26.983706] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:21:26.983734] LOG: [CONN] Sending ping: @[MapperBot] 47.36569, -122.07524 [0.3w] -[2026-02-20T18:21:27.018156] LOG: [CONN] Frame received (109 bytes): 88 2c c2 15 16 c7 32 75 62 54 1e 29 1f 5a 15 e0 53 e3 07 7e 75 20 20 53 7a db cc 81 ad 91 b4 df e8 bc be 71 c5 4e ae 26 6f d7 e7 7b 60 e3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb b0 b6 80 50 07 a5 6f c4 46 11 95 1f 51 a1 4a 81 b8 f8 3d 49 8e 45 50 13 43 aa 3a 28 51 2a e4 -[2026-02-20T18:21:27.018223] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:27.018234] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:27.018263] LOG: [RX PARSE] RAW Packet (106 bytes): 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:27.018270] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:27.018273] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T18:21:27.018286] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xc7, lastHop=0xcc, SNR=11.0, RSSI=-62, payload=82 bytes -[2026-02-20T18:21:27.018291] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T18:21:27.018294] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:21:27.018300] LOG: [TX LOG] Processing rx_log entry: SNR=11.0, RSSI=-62 -[2026-02-20T18:21:27.018303] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:21:27.018309] LOG: [TX LOG] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:21:27.018312] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:21:27.018315] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:21:27.018320] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:21:27.018324] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:21:27.018391] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:27.018402] LOG: [MESSAGE_CORRELATION] ❌ REJECT: Failed to decrypt message: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:27.018408] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:27.018411] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:27.018436] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:27.018439] LOG: [RX FILTER] Raw packet (106 bytes): 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:27.018446] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 11.0 -[2026-02-20T18:21:27.018450] LOG: [RX FILTER] ✓ RSSI OK (-62 < -30) -[2026-02-20T18:21:27.018454] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:27.018458] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:27.018461] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:27.018466] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:21:27.018470] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:21:27.018511] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:27.018543] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:27.018587] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) - - -[2026-02-20T18:21:27.018619] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:27.018622] LOG: [RX LOG] Dropped packet hex: 15 16 C7 32 75 62 54 1E 29 1F 5A 15 E0 53 E3 07 7E 75 20 20 53 7A DB CC 81 AD 91 B4 DF E8 BC BE 71 C5 4E AE 26 6F D7 E7 7B 60 E3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB B0 B6 80 50 07 A5 6F C4 46 11 95 1F 51 A1 4A 81 B8 F8 3D 49 8E 45 50 13 43 AA 3A 28 51 2A E4 -[2026-02-20T18:21:27.042111] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:21:27.042245] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:21:27.042265] LOG: [CONN] Received OK response -[2026-02-20T18:21:27.603161] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:21:27.603435] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:27.709057] LOG: [CONN] Frame received (11 bytes): 0c f0 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:21:27.709214] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:21:27.709233] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:21:27.709256] LOG: [CONN] Battery updated: 4080mV (90%) -[2026-02-20T18:21:27.767079] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c2 2c 11 00 00 00 9d 23 00 00 -[2026-02-20T18:21:27.767172] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:27.767191] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:28.009405] LOG: [GPS SERVICE] Position stream fired: lat=47.36622, lon=-122.07525, accuracy=3.8m -[2026-02-20T18:21:28.009490] LOG: [RX BATCH] Checking 2 active batch(es) for distance trigger -[2026-02-20T18:21:28.009502] LOG: [RX BATCH] Distance check for repeater DB: 59.18m from first observation (threshold=25m) -[2026-02-20T18:21:28.009506] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush -[2026-02-20T18:21:28.009513] LOG: [RX BATCH] Distance check for repeater CC: 59.18m from first observation (threshold=25m) -[2026-02-20T18:21:28.009516] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:21:28.009519] LOG: [RX BATCH] Flushing repeater DB -[2026-02-20T18:21:28.009526] LOG: [RX BATCH] Cleared timeout timer for repeater DB -[2026-02-20T18:21:28.009532] LOG: [RX BATCH] Posting repeater DB: snr=-3.25, location=47.36569,-122.07524 -[2026-02-20T18:21:28.009536] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:28.009542] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=-3.25, location=47.36569,-122.07524 -[2026-02-20T18:21:28.009548] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best -3.25 <= pin -3.25 -[2026-02-20T18:21:28.009554] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=1 -[2026-02-20T18:21:28.009560] LOG: [APP] Added RX log entry: repeater=DB, snr=-3.25, pathLen=13 -[2026-02-20T18:21:28.009576] LOG: [RX BATCH] Repeater DB removed from buffer -[2026-02-20T18:21:28.009579] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:21:28.009584] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:21:28.009588] LOG: [RX BATCH] Posting repeater CC: snr=12.25, location=47.36569,-122.07524 -[2026-02-20T18:21:28.009590] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:28.009596] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.25, location=47.36569,-122.07524 -[2026-02-20T18:21:28.009600] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.25 <= pin 12.25 -[2026-02-20T18:21:28.009605] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:21:28.009609] LOG: [APP] Added RX log entry: repeater=CC, snr=12.25, pathLen=14 -[2026-02-20T18:21:28.009617] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:21:28.009620] LOG: [RX BATCH] Flushed 2 repeater(s) due to GPS movement -[2026-02-20T18:21:29.100761] LOG: [CONN] Frame received (73 bytes): 88 33 c1 15 01 cc 81 1d c9 ec 66 57 3e 6d d4 d4 56 e6 51 69 55 52 72 29 20 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 73 45 60 83 49 9f ac 54 b1 3f 61 af 4e e1 44 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:21:29.100885] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:29.100909] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:29.100962] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 1D C9 EC 66 57 3E 6D D4 D4 56 E6 51 69 55 52 72 29 20 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 73 45 60 83 49 9F AC 54 B1 3F 61 AF 4E E1 44 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:21:29.100978] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:29.100987] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:21:29.101011] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.75, RSSI=-63, payload=67 bytes -[2026-02-20T18:21:29.101026] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:21:29.101036] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:21:29.101046] LOG: [TX LOG] Processing rx_log entry: SNR=12.75, RSSI=-63 -[2026-02-20T18:21:29.101059] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:21:29.101067] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:21:29.101080] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:29.101088] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:29.101096] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:21:30.043070] LOG: [PING] Ping sent successfully -[2026-02-20T18:21:30.566818] LOG: [CONN] Frame received (74 bytes): 88 11 8f 15 02 cc db 81 1d c9 ec 66 57 3e 6d d4 d4 56 e6 51 69 55 52 72 29 20 4a 0d c3 fd 59 75 a3 35 1e 46 81 10 e6 cf 13 da 73 45 60 83 49 9f ac 54 b1 3f 61 af 4e e1 44 9e 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:21:30.566882] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:30.566894] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:30.566918] LOG: [RX PARSE] RAW Packet (71 bytes): 15 02 CC DB 81 1D C9 EC 66 57 3E 6D D4 D4 56 E6 51 69 55 52 72 29 20 4A 0D C3 FD 59 75 A3 35 1E 46 81 10 E6 CF 13 DA 73 45 60 83 49 9F AC 54 B1 3F 61 AF 4E E1 44 9E 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:21:30.566922] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:30.566928] LOG: [RX PARSE] Path length offset: 1, Path length: 2 -[2026-02-20T18:21:30.566940] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=2, firstHop=0xcc, lastHop=0xdb, SNR=4.25, RSSI=-113, payload=67 bytes -[2026-02-20T18:21:30.566946] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=2 -[2026-02-20T18:21:30.566951] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:21:30.566955] LOG: [TX LOG] Processing rx_log entry: SNR=4.25, RSSI=-113 -[2026-02-20T18:21:30.566960] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:21:30.566964] LOG: [TX LOG] CARpeater pass-through: stripped cc, reporting underlying repeater db -[2026-02-20T18:21:30.566967] LOG: [TX LOG] RSSI check skipped (CARpeater pass-through) -[2026-02-20T18:21:30.566973] LOG: [TX LOG] Message correlation check: packet_channel_hash=0x81, expected=0x81 -[2026-02-20T18:21:30.566976] LOG: [TX LOG] Channel hash match confirmed - this is a message on our channel -[2026-02-20T18:21:30.566979] LOG: [MESSAGE_CORRELATION] Channel key available, attempting decryption... -[2026-02-20T18:21:30.566986] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:21:30.567019] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:21:30.567057] LOG: [MESSAGE_CORRELATION] Decryption successful, comparing content... -[2026-02-20T18:21:30.567061] LOG: [MESSAGE_CORRELATION] Decrypted: "Cozmo: @[MapperBot] 47.36569, -122.07524 [0.3w]" (47 chars) -[2026-02-20T18:21:30.567068] LOG: [MESSAGE_CORRELATION] Expected: "@[MapperBot] 47.36569, -122.07524 [0.3w]" (40 chars) -[2026-02-20T18:21:30.567071] LOG: [MESSAGE_CORRELATION] ✅ Message contained in decrypted text (with sender prefix) - this is an echo of our ping! -[2026-02-20T18:21:30.567077] LOG: [PING] Repeater echo accepted: first_hop=db, SNR=null, full_path_length=2 (CARpeater stripped) -[2026-02-20T18:21:30.567085] LOG: [PING] Adding new repeater echo: path=db, SNR=null, RSSI=null -[2026-02-20T18:21:30.567090] LOG: [TX LOG] Invoking onEchoReceived callback (callback=SET) -[2026-02-20T18:21:30.567096] LOG: [PING] onEchoReceived callback fired: db, SNR=null, RSSI=null, isNew=true -[2026-02-20T18:21:30.567103] LOG: [PING] Real-time: Added new repeater db (SNR: null) - total: 1 -[2026-02-20T18:21:30.567107] LOG: [PING] Calling onEchoReceived callback (callback=SET) -[2026-02-20T18:21:30.567113] LOG: [APP] ========== ECHO CALLBACK RECEIVED ========== -[2026-02-20T18:21:30.567118] LOG: [APP] Real-time echo: db (SNR: null, isNew: true) -[2026-02-20T18:21:30.567121] LOG: [APP] TxLogEntries count: 35 -[2026-02-20T18:21:30.567127] LOG: [APP] Updated TxLogEntry with 1 events (real-time) -[2026-02-20T18:21:30.567130] LOG: [APP] Calling notifyListeners() to update UI -[2026-02-20T18:21:30.567134] LOG: [APP] notifyListeners() completed -[2026-02-20T18:21:30.567139] LOG: [PING] onEchoReceived callback completed -[2026-02-20T18:21:30.567143] LOG: [TX LOG] onEchoReceived callback invoked successfully -[2026-02-20T18:21:30.567146] LOG: [TX LOG] ✅ Echo tracked successfully -[2026-02-20T18:21:30.567152] LOG: [UNIFIED RX] Packet was TX echo, done -[2026-02-20T18:21:31.984674] LOG: [TX LOG] Stopping echo tracking (heard 1 repeaters) -[2026-02-20T18:21:31.984736] LOG: [TX LOG] Final: db -> SNR=null, seen=1x -[2026-02-20T18:21:32.462317] LOG: [CONN] Frame received (78 bytes): 88 23 9a 15 06 af d1 7a 74 32 db 11 34 1f 25 18 a3 2b 3a e9 f4 c0 d9 9b 67 37 a2 4b fd bb cc f6 88 74 66 88 f6 06 15 c6 13 4e 32 d5 9f 44 b3 8f d7 97 36 33 13 b4 82 75 c3 86 0b 6c d1 6f 16 99 8a 81 b8 1a 6c e6 5e 0e a5 12 55 de 50 49 -[2026-02-20T18:21:32.462428] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:32.462448] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:32.462593] LOG: [RX PARSE] RAW Packet (75 bytes): 15 06 AF D1 7A 74 32 DB 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 -[2026-02-20T18:21:32.462612] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:32.462663] LOG: [RX PARSE] Path length offset: 1, Path length: 6 -[2026-02-20T18:21:32.462693] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=6, firstHop=0xaf, lastHop=0xdb, SNR=8.75, RSSI=-102, payload=67 bytes -[2026-02-20T18:21:32.462703] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=6 -[2026-02-20T18:21:32.462715] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:32.462723] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:32.462781] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:32.462790] LOG: [RX FILTER] Raw packet (75 bytes): 15 06 AF D1 7A 74 32 DB 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 -[2026-02-20T18:21:32.462808] LOG: [RX FILTER] Header: 0x15 | PathLength: 6 | SNR: 8.75 -[2026-02-20T18:21:32.462818] LOG: [RX FILTER] ✓ RSSI OK (-102 < -30) -[2026-02-20T18:21:32.462830] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:32.462842] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:21:32.462850] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:21:32.462864] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:21:32.462874] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:21:32.462942] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:21:32.463083] LOG: [RX FILTER] Decrypted message (45 chars): "WXDev H3 : @[hankest] ack, Lynnwood, 3 hops" -[2026-02-20T18:21:32.463105] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) -[2026-02-20T18:21:32.463115] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:32.463139] LOG: [RX LOG] Packet heard via last hop: DB, SNR=8.75, path_length=6 -[2026-02-20T18:21:32.463148] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:32.463160] LOG: [RX BATCH] First observation for repeater DB: SNR=8.75 -[2026-02-20T18:21:32.463178] LOG: [RX BATCH] Started 30s timeout timer for repeater DB -[2026-02-20T18:21:32.463194] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:32.463213] LOG: [APP] Immediate RX observation: repeater=DB, snr=8.75, location=47.36622,-122.07525 -[2026-02-20T18:21:32.463228] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:21:32.463247] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36622,-122.07525 (batch tracking: 1 repeaters, rxCount: 37) -[2026-02-20T18:21:32.463264] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:32.463284] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=8.75, location=47.36622,-122.07525 -[2026-02-20T18:21:32.463628] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:21:32.463638] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:21:32.463650] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:21:32.603056] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:32.652865] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 9a 23 11 00 00 00 9e 23 00 00 -[2026-02-20T18:21:32.653018] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:32.653041] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:21:34.009848] LOG: [GPS SERVICE] Position stream fired: lat=47.36683, lon=-122.07525, accuracy=3.8m -[2026-02-20T18:21:34.009958] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:21:34.009970] LOG: [RX BATCH] Distance check for repeater DB: 67.66m from first observation (threshold=25m) -[2026-02-20T18:21:34.009977] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush -[2026-02-20T18:21:34.009982] LOG: [RX BATCH] Flushing repeater DB -[2026-02-20T18:21:34.009989] LOG: [RX BATCH] Cleared timeout timer for repeater DB -[2026-02-20T18:21:34.009998] LOG: [RX BATCH] Posting repeater DB: snr=8.75, location=47.36622,-122.07525 -[2026-02-20T18:21:34.010003] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:34.010007] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=8.75, location=47.36622,-122.07525 -[2026-02-20T18:21:34.010018] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 8.75 <= pin 8.75 -[2026-02-20T18:21:34.010023] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=0 -[2026-02-20T18:21:34.010030] LOG: [APP] Added RX log entry: repeater=DB, snr=8.75, pathLen=6 -[2026-02-20T18:21:34.010050] LOG: [RX BATCH] Repeater DB removed from buffer -[2026-02-20T18:21:34.010055] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:21:34.541614] LOG: [CONN] Frame received (79 bytes): 88 2e c7 15 07 af d1 7a 74 32 db cc 11 34 1f 25 18 a3 2b 3a e9 f4 c0 d9 9b 67 37 a2 4b fd bb cc f6 88 74 66 88 f6 06 15 c6 13 4e 32 d5 9f 44 b3 8f d7 97 36 33 13 b4 82 75 c3 86 0b 6c d1 6f 16 99 8a 81 b8 1a 6c e6 5e 0e a5 12 55 de 50 49 -[2026-02-20T18:21:34.541683] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:34.541695] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:34.541717] LOG: [RX PARSE] RAW Packet (76 bytes): 15 07 AF D1 7A 74 32 DB CC 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 -[2026-02-20T18:21:34.541723] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:34.541725] LOG: [RX PARSE] Path length offset: 1, Path length: 7 -[2026-02-20T18:21:34.541738] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=7, firstHop=0xaf, lastHop=0xcc, SNR=11.5, RSSI=-57, payload=67 bytes -[2026-02-20T18:21:34.541743] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=7 -[2026-02-20T18:21:34.541745] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:34.541749] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:34.541772] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:34.541775] LOG: [RX FILTER] Raw packet (76 bytes): 15 07 AF D1 7A 74 32 DB CC 11 34 1F 25 18 A3 2B 3A E9 F4 C0 D9 9B 67 37 A2 4B FD BB CC F6 88 74 66 88 F6 06 15 C6 13 4E 32 D5 9F 44 B3 8F D7 97 36 33 13 B4 82 75 C3 86 0B 6C D1 6F 16 99 8A 81 B8 1A 6C E6 5E 0E A5 12 55 DE 50 49 -[2026-02-20T18:21:34.541782] LOG: [RX FILTER] Header: 0x15 | PathLength: 7 | SNR: 11.5 -[2026-02-20T18:21:34.541786] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:21:34.541789] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:34.541794] LOG: [RX FILTER] Channel hash: 0x11 -[2026-02-20T18:21:34.541799] LOG: [RX FILTER] ✓ Channel matched: Public -[2026-02-20T18:21:34.541802] LOG: [RX FILTER] Encrypted message: 64 bytes -[2026-02-20T18:21:34.541807] LOG: [CRYPTO] Decrypting message (64 bytes) -[2026-02-20T18:21:34.541835] LOG: [CRYPTO] Decrypted successfully (64 bytes) -[2026-02-20T18:21:34.541901] LOG: [RX FILTER] Decrypted message (45 chars): "WXDev H3 : @[hankest] ack, Lynnwood, 3 hops" -[2026-02-20T18:21:34.541908] LOG: [RX FILTER] Printable ratio: 95.6% (threshold: 60.0%) -[2026-02-20T18:21:34.541910] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:34.541921] LOG: [RX LOG] Packet heard via last hop: CC, SNR=11.5, path_length=7 -[2026-02-20T18:21:34.541925] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:34.541931] LOG: [RX BATCH] First observation for repeater CC: SNR=11.5 -[2026-02-20T18:21:34.541941] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:21:34.541948] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:34.541953] LOG: [APP] Immediate RX observation: repeater=CC, snr=11.5, location=47.36683,-122.07525 -[2026-02-20T18:21:34.541961] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:21:34.541968] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36683,-122.07525 (batch tracking: 1 repeaters, rxCount: 38) -[2026-02-20T18:21:34.541977] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:21:34.541983] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=11.5, location=47.36683,-122.07525 -[2026-02-20T18:21:35.043730] LOG: [PING] RX listening window ended -[2026-02-20T18:21:35.043855] LOG: [PING] TxTracker collected 1 repeater echoes -[2026-02-20T18:21:35.043869] LOG: [PING] Heard repeater: db, SNR=null -[2026-02-20T18:21:35.044038] LOG: [GRAPH] Recorded txSuccess event at -119dBm with 1 repeater(s) -[2026-02-20T18:21:35.044082] LOG: [PING] Queued TX entry with heard_repeats: db(null) -[2026-02-20T18:21:35.044091] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:21:35.044098] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:21:35.044114] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:21:35.044122] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:21:35.044514] LOG: [API QUEUE] TX enqueued: db(null) (queue size: 1) -[2026-02-20T18:21:37.573642] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:21:37.573728] LOG: [API QUEUE] Item 1/2: type=TX, external_antenna=true -[2026-02-20T18:21:37.573734] LOG: [API QUEUE] Item 2/2: type=RX, external_antenna=true -[2026-02-20T18:21:37.573737] LOG: [API QUEUE] Uploading 2 items... -[2026-02-20T18:21:37.579132] LOG: [API QUEUE] Flushed 3 RX items from 2 repeaters to queue -[2026-02-20T18:21:37.602697] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:37.783573] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c7 2e 11 00 00 00 9e 23 00 00 -[2026-02-20T18:21:37.783706] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:37.783726] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:38.118960] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:21:38.119055] LOG: [API] Request: {"data":"2 items","items":"TX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:21:38.119074] LOG: [API] Response (200) in 0.55s: {"success":true,"expires_at":1771640797} -[2026-02-20T18:21:38.119093] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:21:38.119117] LOG: [API] Upload batch SUCCESS: 2 items -[2026-02-20T18:21:38.119944] LOG: [API QUEUE] Upload SUCCESS: deleted 2 items -[2026-02-20T18:21:38.119961] LOG: [APP] Upload success: +2 items (total: 70) -[2026-02-20T18:21:39.077107] LOG: [GPS SERVICE] Position stream fired: lat=47.36708, lon=-122.07502, accuracy=3.8m -[2026-02-20T18:21:39.077201] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:21:39.077211] LOG: [RX BATCH] Distance check for repeater CC: 32.47m from first observation (threshold=25m) -[2026-02-20T18:21:39.077216] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:21:39.077220] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:21:39.077226] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:21:39.077234] LOG: [RX BATCH] Posting repeater CC: snr=11.5, location=47.36683,-122.07525 -[2026-02-20T18:21:39.077238] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:39.077242] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=11.5, location=47.36683,-122.07525 -[2026-02-20T18:21:39.077250] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 11.50 <= pin 11.50 -[2026-02-20T18:21:39.077257] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:21:39.077263] LOG: [APP] Added RX log entry: repeater=CC, snr=11.5, pathLen=7 -[2026-02-20T18:21:39.077280] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:21:39.077285] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:21:40.045636] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:21:40.045914] LOG: [API QUEUE] Item 1/3: type=RX, external_antenna=true -[2026-02-20T18:21:40.045927] LOG: [API QUEUE] Item 2/3: type=RX, external_antenna=true -[2026-02-20T18:21:40.045936] LOG: [API QUEUE] Item 3/3: type=RX, external_antenna=true -[2026-02-20T18:21:40.045948] LOG: [API QUEUE] Uploading 3 items... -[2026-02-20T18:21:40.046999] LOG: [API QUEUE] Flushed 1 RX items from 1 repeaters to queue -[2026-02-20T18:21:40.436141] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:21:40.436247] LOG: [API] Request: {"data":"3 items","items":"RX:external_antenna=true, RX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:21:40.436266] LOG: [API] Response (200) in 0.39s: {"success":true,"expires_at":1771640800} -[2026-02-20T18:21:40.436283] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:21:40.436309] LOG: [API] Upload batch SUCCESS: 3 items -[2026-02-20T18:21:40.441348] LOG: [API QUEUE] Upload SUCCESS: deleted 3 items -[2026-02-20T18:21:40.441386] LOG: [APP] Upload success: +3 items (total: 73) -[2026-02-20T18:21:42.231873] LOG: [CONN] Frame received (91 bytes): 88 0f 8f 15 03 e8 7e 02 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 -[2026-02-20T18:21:42.231933] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:42.231974] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:42.232055] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:42.232079] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:42.232091] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:21:42.232121] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x02, SNR=3.75, RSSI=-113, payload=83 bytes -[2026-02-20T18:21:42.232141] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:21:42.232151] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:42.232166] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:42.232253] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:42.232264] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:42.232289] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 3.75 -[2026-02-20T18:21:42.232303] LOG: [RX FILTER] ✓ RSSI OK (-113 < -30) -[2026-02-20T18:21:42.232319] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:42.232331] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:42.232343] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:42.232360] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:42.232372] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:42.232473] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:42.232663] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." -[2026-02-20T18:21:42.232694] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:42.232706] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:42.232828] LOG: [RX LOG] Packet heard via last hop: 02, SNR=3.75, path_length=3 -[2026-02-20T18:21:42.232841] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:42.232862] LOG: [RX BATCH] First observation for repeater 02: SNR=3.75 -[2026-02-20T18:21:42.232878] LOG: [RX BATCH] Started 30s timeout timer for repeater 02 -[2026-02-20T18:21:42.232902] LOG: [RX BATCH] Distance check for repeater 02: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:42.232923] LOG: [APP] Immediate RX observation: repeater=02, snr=3.75, location=47.36708,-122.07502 -[2026-02-20T18:21:42.232946] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:21:42.232966] LOG: [APP] Created IMMEDIATE RX pin for repeater: 02 at 47.36708,-122.07502 (batch tracking: 1 repeaters, rxCount: 39) -[2026-02-20T18:21:42.232986] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:42.233010] LOG: [RX LOG] ✅ Observation kept in batch: repeater=02, snr=3.75, location=47.36708,-122.07502 -[2026-02-20T18:21:42.233491] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:21:42.233511] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:21:42.233523] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:21:42.506980] LOG: [CONN] Frame received (91 bytes): 88 0e 8e 15 03 e8 7e 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 -[2026-02-20T18:21:42.507100] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:42.507128] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:42.507207] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:42.507229] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:42.507241] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:21:42.507271] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x6c, SNR=3.5, RSSI=-114, payload=83 bytes -[2026-02-20T18:21:42.507282] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:21:42.507295] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:42.507304] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:42.507363] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:42.507377] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:42.507391] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 3.5 -[2026-02-20T18:21:42.507409] LOG: [RX FILTER] ✓ RSSI OK (-114 < -30) -[2026-02-20T18:21:42.507418] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:42.507425] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:42.507440] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:42.507450] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:42.507457] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:42.507558] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:42.507612] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." -[2026-02-20T18:21:42.507629] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:42.507635] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:42.507661] LOG: [RX LOG] Packet heard via last hop: 6C, SNR=3.5, path_length=3 -[2026-02-20T18:21:42.507673] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:42.507687] LOG: [RX BATCH] First observation for repeater 6C: SNR=3.5 -[2026-02-20T18:21:42.507700] LOG: [RX BATCH] Started 30s timeout timer for repeater 6C -[2026-02-20T18:21:42.507720] LOG: [RX BATCH] Distance check for repeater 6C: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:42.507736] LOG: [APP] Immediate RX observation: repeater=6C, snr=3.5, location=47.36708,-122.07502 -[2026-02-20T18:21:42.507764] LOG: [APP] Current batch tracking: 1 repeaters: {02} -[2026-02-20T18:21:42.507781] LOG: [APP] Created IMMEDIATE RX pin for repeater: 6C at 47.36708,-122.07502 (batch tracking: 2 repeaters, rxCount: 40) -[2026-02-20T18:21:42.507801] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:42.507816] LOG: [RX LOG] ✅ Observation kept in batch: repeater=6C, snr=3.5, location=47.36708,-122.07502 -[2026-02-20T18:21:42.604342] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:42.706594] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff 8e 0e 11 00 00 00 9f 23 00 00 -[2026-02-20T18:21:42.706723] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:42.706748] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:43.558047] LOG: [CONN] Frame received (91 bytes): 88 29 9d 15 03 e8 7e db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 -[2026-02-20T18:21:43.558107] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:43.558117] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:43.558142] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:43.558148] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:43.558154] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:21:43.558163] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xdb, SNR=10.25, RSSI=-99, payload=83 bytes -[2026-02-20T18:21:43.558168] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:21:43.558172] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:43.558175] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:43.558195] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:43.558201] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:43.558207] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 10.25 -[2026-02-20T18:21:43.558213] LOG: [RX FILTER] ✓ RSSI OK (-99 < -30) -[2026-02-20T18:21:43.558216] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:43.558220] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:43.558225] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:43.558228] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:43.558233] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:43.558262] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:43.558328] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." -[2026-02-20T18:21:43.558334] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:43.558338] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:43.558348] LOG: [RX LOG] Packet heard via last hop: DB, SNR=10.25, path_length=3 -[2026-02-20T18:21:43.558353] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:43.558358] LOG: [RX BATCH] First observation for repeater DB: SNR=10.25 -[2026-02-20T18:21:43.558366] LOG: [RX BATCH] Started 30s timeout timer for repeater DB -[2026-02-20T18:21:43.558374] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:43.558380] LOG: [APP] Immediate RX observation: repeater=DB, snr=10.25, location=47.36708,-122.07502 -[2026-02-20T18:21:43.558387] LOG: [APP] Current batch tracking: 2 repeaters: {02, 6C} -[2026-02-20T18:21:43.558393] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36708,-122.07502 (batch tracking: 3 repeaters, rxCount: 41) -[2026-02-20T18:21:43.558401] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:43.558407] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=10.25, location=47.36708,-122.07502 -[2026-02-20T18:21:43.744845] LOG: [GPS SERVICE] Position stream fired: lat=47.36709, lon=-122.07439, accuracy=3.8m -[2026-02-20T18:21:43.744944] LOG: [RX BATCH] Checking 3 active batch(es) for distance trigger -[2026-02-20T18:21:43.744959] LOG: [RX BATCH] Distance check for repeater 02: 47.61m from first observation (threshold=25m) -[2026-02-20T18:21:43.744963] LOG: [RX BATCH] Distance threshold met for repeater 02, marking for flush -[2026-02-20T18:21:43.744967] LOG: [RX BATCH] Distance check for repeater 6C: 47.61m from first observation (threshold=25m) -[2026-02-20T18:21:43.744973] LOG: [RX BATCH] Distance threshold met for repeater 6C, marking for flush -[2026-02-20T18:21:43.744977] LOG: [RX BATCH] Distance check for repeater DB: 47.61m from first observation (threshold=25m) -[2026-02-20T18:21:43.744981] LOG: [RX BATCH] Distance threshold met for repeater DB, marking for flush -[2026-02-20T18:21:43.744986] LOG: [RX BATCH] Flushing repeater 02 -[2026-02-20T18:21:43.744991] LOG: [RX BATCH] Cleared timeout timer for repeater 02 -[2026-02-20T18:21:43.744999] LOG: [RX BATCH] Posting repeater 02: snr=3.75, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745002] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:43.745007] LOG: [APP] Finalized RX entry (best SNR): repeater=02, snr=3.75, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745018] LOG: [APP] RX pin SNR unchanged for repeater=02: batch best 3.75 <= pin 3.75 -[2026-02-20T18:21:43.745023] LOG: [APP] Cleared batch tracking for 02: wasPresent=true, remaining=2 -[2026-02-20T18:21:43.745030] LOG: [APP] Added RX log entry: repeater=02, snr=3.75, pathLen=3 -[2026-02-20T18:21:43.745051] LOG: [RX BATCH] Repeater 02 removed from buffer -[2026-02-20T18:21:43.745056] LOG: [RX BATCH] Flushing repeater 6C -[2026-02-20T18:21:43.745060] LOG: [RX BATCH] Cleared timeout timer for repeater 6C -[2026-02-20T18:21:43.745068] LOG: [RX BATCH] Posting repeater 6C: snr=3.5, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745071] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:43.745074] LOG: [APP] Finalized RX entry (best SNR): repeater=6C, snr=3.5, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745082] LOG: [APP] RX pin SNR unchanged for repeater=6C: batch best 3.50 <= pin 3.50 -[2026-02-20T18:21:43.745086] LOG: [APP] Cleared batch tracking for 6C: wasPresent=true, remaining=1 -[2026-02-20T18:21:43.745091] LOG: [APP] Added RX log entry: repeater=6C, snr=3.5, pathLen=3 -[2026-02-20T18:21:43.745097] LOG: [RX BATCH] Repeater 6C removed from buffer -[2026-02-20T18:21:43.745104] LOG: [RX BATCH] Flushing repeater DB -[2026-02-20T18:21:43.745107] LOG: [RX BATCH] Cleared timeout timer for repeater DB -[2026-02-20T18:21:43.745111] LOG: [RX BATCH] Posting repeater DB: snr=10.25, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745114] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:43.745117] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=10.25, location=47.36708,-122.07502 -[2026-02-20T18:21:43.745124] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 10.25 <= pin 10.25 -[2026-02-20T18:21:43.745126] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=0 -[2026-02-20T18:21:43.745129] LOG: [APP] Added RX log entry: repeater=DB, snr=10.25, pathLen=3 -[2026-02-20T18:21:43.745137] LOG: [RX BATCH] Repeater DB removed from buffer -[2026-02-20T18:21:43.745155] LOG: [RX BATCH] Flushed 3 repeater(s) due to GPS movement -[2026-02-20T18:21:44.208887] LOG: [CONN] Frame received (92 bytes): 88 30 cc 15 04 e8 7e 02 cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 e4 c2 b7 -[2026-02-20T18:21:44.209068] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:44.209090] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:44.209145] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 E8 7E 02 CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:44.209157] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:44.209167] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:21:44.209189] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-52, payload=83 bytes -[2026-02-20T18:21:44.209206] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:21:44.209212] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:44.209218] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:44.209267] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:44.209275] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 E8 7E 02 CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 E4 C2 B7 -[2026-02-20T18:21:44.209289] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 -[2026-02-20T18:21:44.209299] LOG: [RX FILTER] ✓ RSSI OK (-52 < -30) -[2026-02-20T18:21:44.209305] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:44.209315] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:44.209324] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:44.209331] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:21:44.209341] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:21:44.209407] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:21:44.209528] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.34049, -122.52174 [..." -[2026-02-20T18:21:44.209543] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:21:44.209552] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:21:44.209573] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 -[2026-02-20T18:21:44.209579] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:21:44.209589] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 -[2026-02-20T18:21:44.209604] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:21:44.209616] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:21:44.209632] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.36709,-122.07439 -[2026-02-20T18:21:44.209645] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:21:44.209658] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36709,-122.07439 (batch tracking: 1 repeaters, rxCount: 42) -[2026-02-20T18:21:44.209676] LOG: [GRAPH] Recorded rx event at -118dBm with 1 repeater(s) -[2026-02-20T18:21:44.209689] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.36709,-122.07439 -[2026-02-20T18:21:45.441642] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:21:47.603389] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:47.716056] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff cc 30 11 00 00 00 9f 23 00 00 -[2026-02-20T18:21:47.716185] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:47.716205] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:49.073771] LOG: [GPS SERVICE] Position stream fired: lat=47.36709, lon=-122.07367, accuracy=3.8m -[2026-02-20T18:21:49.073878] LOG: [RX BATCH] Checking 1 active batch(es) for distance trigger -[2026-02-20T18:21:49.073895] LOG: [RX BATCH] Distance check for repeater CC: 54.02m from first observation (threshold=25m) -[2026-02-20T18:21:49.073899] LOG: [RX BATCH] Distance threshold met for repeater CC, marking for flush -[2026-02-20T18:21:49.073903] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:21:49.073913] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:21:49.073922] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.36709,-122.07439 -[2026-02-20T18:21:49.073927] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:21:49.073931] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.36709,-122.07439 -[2026-02-20T18:21:49.073939] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 -[2026-02-20T18:21:49.073947] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:21:49.073952] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 -[2026-02-20T18:21:49.074023] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:21:49.074030] LOG: [RX BATCH] Flushed 1 repeater(s) due to GPS movement -[2026-02-20T18:21:49.564967] LOG: [CONN] Frame received (95 bytes): 88 27 97 15 0a e8 7e 75 20 20 20 20 53 7e db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 -[2026-02-20T18:21:49.565028] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:49.565044] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:49.565076] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:49.565086] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:49.565091] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:21:49.565107] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xe8, lastHop=0xdb, SNR=9.75, RSSI=-105, payload=80 bytes -[2026-02-20T18:21:49.565114] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:21:49.565118] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:49.565124] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:49.565160] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:49.565164] LOG: [RX FILTER] Raw packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:49.565173] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 9.75 -[2026-02-20T18:21:49.565178] LOG: [RX FILTER] ✓ RSSI OK (-105 < -30) -[2026-02-20T18:21:49.565185] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:49.565190] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:49.565194] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:49.565201] LOG: [RX FILTER] Encrypted message: 77 bytes -[2026-02-20T18:21:49.565207] LOG: [CRYPTO] Decrypting message (77 bytes) -[2026-02-20T18:21:49.565286] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:49.565304] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:49.565405] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:49.565470] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:49.565475] LOG: [RX LOG] Dropped packet hex: 15 0A E8 7E 75 20 20 20 20 53 7E DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:50.421584] LOG: [CONN] Frame received (95 bytes): 88 31 c4 15 0a e8 7e 75 20 20 20 20 53 7e cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e ac 5b 72 58 -[2026-02-20T18:21:50.421760] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:50.421800] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:50.421888] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:50.421913] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:50.421925] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:21:50.421957] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=10, firstHop=0xe8, lastHop=0xcc, SNR=12.25, RSSI=-60, payload=80 bytes -[2026-02-20T18:21:50.421978] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=10 -[2026-02-20T18:21:50.421989] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:50.422004] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:50.422097] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:50.422110] LOG: [RX FILTER] Raw packet (92 bytes): 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:50.422135] LOG: [RX FILTER] Header: 0x15 | PathLength: 10 | SNR: 12.25 -[2026-02-20T18:21:50.422150] LOG: [RX FILTER] ✓ RSSI OK (-60 < -30) -[2026-02-20T18:21:50.422165] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:50.422178] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:50.422190] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:50.422207] LOG: [RX FILTER] Encrypted message: 77 bytes -[2026-02-20T18:21:50.422219] LOG: [CRYPTO] Decrypting message (77 bytes) -[2026-02-20T18:21:50.422432] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:50.422490] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:50.422755] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:50.422832] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:50.422840] LOG: [RX LOG] Dropped packet hex: 15 0A E8 7E 75 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E AC 5B 72 58 -[2026-02-20T18:21:52.573666] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:21:52.573789] LOG: [API QUEUE] Item 1/1: type=RX, external_antenna=true -[2026-02-20T18:21:52.573798] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:21:52.575343] LOG: [API QUEUE] Flushed 4 RX items from 4 repeaters to queue -[2026-02-20T18:21:52.602851] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:52.726718] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c4 31 11 00 00 00 a0 23 00 00 -[2026-02-20T18:21:52.726825] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:52.726840] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:53.075015] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:21:53.075069] LOG: [API] Request: {"data":"1 items","items":"RX:external_antenna=true"} -[2026-02-20T18:21:53.075083] LOG: [API] Response (200) in 0.50s: {"success":true,"expires_at":1771640812} -[2026-02-20T18:21:53.075095] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:21:53.075110] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:21:53.075353] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:21:53.075368] LOG: [APP] Upload success: +1 items (total: 74) -[2026-02-20T18:21:54.073835] LOG: [GPS SERVICE] Position stream fired: lat=47.36733, lon=-122.07340, accuracy=3.8m -[2026-02-20T18:21:54.073936] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:21:54.073965] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:21:56.131405] LOG: [CONN] Frame received (95 bytes): 88 24 99 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 c7 db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e -[2026-02-20T18:21:56.131590] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:56.131624] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:56.131725] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.131745] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:56.131763] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:21:56.131805] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xdb, SNR=9.0, RSSI=-103, payload=76 bytes -[2026-02-20T18:21:56.131824] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:21:56.131837] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:56.131846] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:56.131924] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:56.131943] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.132041] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 9.0 -[2026-02-20T18:21:56.132057] LOG: [RX FILTER] ✓ RSSI OK (-103 < -30) -[2026-02-20T18:21:56.132069] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:56.132087] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:56.132101] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:56.132115] LOG: [RX FILTER] Encrypted message: 73 bytes -[2026-02-20T18:21:56.132134] LOG: [CRYPTO] Decrypting message (73 bytes) -[2026-02-20T18:21:56.132347] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.132402] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.132649] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:56.132784] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:56.132796] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.508603] LOG: [CONN] Frame received (95 bytes): 88 01 8b 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 7e 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e -[2026-02-20T18:21:56.508664] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:56.508705] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:56.508786] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.508809] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:56.508824] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:21:56.508855] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x6c, SNR=0.25, RSSI=-117, payload=76 bytes -[2026-02-20T18:21:56.508868] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:21:56.508883] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:56.508893] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:56.508981] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:56.509033] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.509058] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 0.25 -[2026-02-20T18:21:56.509074] LOG: [RX FILTER] ✓ RSSI OK (-117 < -30) -[2026-02-20T18:21:56.509086] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:56.509100] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:56.509113] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:56.509125] LOG: [RX FILTER] Encrypted message: 73 bytes -[2026-02-20T18:21:56.509140] LOG: [CRYPTO] Decrypting message (73 bytes) -[2026-02-20T18:21:56.509325] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.509484] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.509716] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:56.509844] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:56.509856] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.930380] LOG: [CONN] Frame received (95 bytes): 88 2f c5 15 0e e8 7e 75 20 20 20 20 20 20 20 20 53 7e cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 5e -[2026-02-20T18:21:56.930585] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:21:56.930624] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:21:56.930741] LOG: [RX PARSE] RAW Packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.930764] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:21:56.930776] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:21:56.930811] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xcc, SNR=11.75, RSSI=-59, payload=76 bytes -[2026-02-20T18:21:56.930826] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:21:56.930836] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:21:56.930860] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:21:56.930941] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:21:56.930954] LOG: [RX FILTER] Raw packet (92 bytes): 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:56.931207] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 11.75 -[2026-02-20T18:21:56.931229] LOG: [RX FILTER] ✓ RSSI OK (-59 < -30) -[2026-02-20T18:21:56.931242] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:21:56.931252] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:21:56.931263] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:21:56.931282] LOG: [RX FILTER] Encrypted message: 73 bytes -[2026-02-20T18:21:56.931292] LOG: [CRYPTO] Decrypting message (73 bytes) -[2026-02-20T18:21:56.931480] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.931532] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:21:56.931748] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:21:56.931870] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:21:56.931896] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 20 20 20 53 7E CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 5E -[2026-02-20T18:21:57.602850] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:21:57.603059] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:21:57.737088] LOG: [CONN] Frame received (11 bytes): 0c ec 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:21:57.737230] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:21:57.737253] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:21:57.737269] LOG: [CONN] Battery updated: 4076mV (90%) -[2026-02-20T18:21:57.795534] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff c5 2f 11 00 00 00 a1 23 00 00 -[2026-02-20T18:21:57.795659] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:21:57.795680] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:21:58.076202] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:21:58.759254] LOG: [GPS SERVICE] Position stream fired: lat=47.36765, lon=-122.07335, accuracy=3.8m -[2026-02-20T18:22:00.650280] LOG: [CONN] Frame received (102 bytes): 88 2f a9 15 16 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 -[2026-02-20T18:22:00.650428] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:00.650457] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:00.650613] LOG: [RX PARSE] RAW Packet (99 bytes): 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:00.650655] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:00.650667] LOG: [RX PARSE] Path length offset: 1, Path length: 22 -[2026-02-20T18:22:00.650688] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=22, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-87, payload=75 bytes -[2026-02-20T18:22:00.650707] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=22 -[2026-02-20T18:22:00.650718] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:00.650734] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:00.650819] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:00.650835] LOG: [RX FILTER] Raw packet (99 bytes): 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:00.650857] LOG: [RX FILTER] Header: 0x15 | PathLength: 22 | SNR: 11.75 -[2026-02-20T18:22:00.650875] LOG: [RX FILTER] ✓ RSSI OK (-87 < -30) -[2026-02-20T18:22:00.650886] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:00.650897] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:00.650912] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:00.650924] LOG: [RX FILTER] Encrypted message: 72 bytes -[2026-02-20T18:22:00.650935] LOG: [CRYPTO] Decrypting message (72 bytes) -[2026-02-20T18:22:00.651122] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:00.651174] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:00.651415] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:00.651545] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:00.651557] LOG: [RX LOG] Dropped packet hex: 15 16 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.201473] LOG: [CONN] Frame received (103 bytes): 88 2c 9d 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 6c 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 -[2026-02-20T18:22:01.201645] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:01.201678] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:01.201777] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.201801] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:01.201816] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T18:22:01.201853] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0x6c, SNR=11.0, RSSI=-99, payload=75 bytes -[2026-02-20T18:22:01.201869] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 -[2026-02-20T18:22:01.201879] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:01.201895] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:01.201986] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:01.202011] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.202035] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.0 -[2026-02-20T18:22:01.202056] LOG: [RX FILTER] ✓ RSSI OK (-99 < -30) -[2026-02-20T18:22:01.202067] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:01.202079] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:01.202101] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:01.202114] LOG: [RX FILTER] Encrypted message: 72 bytes -[2026-02-20T18:22:01.202129] LOG: [CRYPTO] Decrypting message (72 bytes) -[2026-02-20T18:22:01.202335] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:01.202389] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:01.202772] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:01.202919] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:01.202937] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 6C 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.731275] LOG: [CONN] Frame received (103 bytes): 88 29 9e 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db 02 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 -[2026-02-20T18:22:01.731336] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:01.731376] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:01.731466] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.731490] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:01.731504] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T18:22:01.731532] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0x02, SNR=10.25, RSSI=-98, payload=75 bytes -[2026-02-20T18:22:01.731552] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 -[2026-02-20T18:22:01.731562] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:01.731589] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:01.731686] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:01.731698] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:01.731723] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 10.25 -[2026-02-20T18:22:01.731742] LOG: [RX FILTER] ✓ RSSI OK (-98 < -30) -[2026-02-20T18:22:01.731754] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:01.731764] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:01.731780] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:01.731793] LOG: [RX FILTER] Encrypted message: 72 bytes -[2026-02-20T18:22:01.731803] LOG: [CRYPTO] Decrypting message (72 bytes) -[2026-02-20T18:22:01.732005] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:01.732163] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:01.732374] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:01.732517] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:01.732535] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB 02 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:02.370240] LOG: [CONN] Frame received (103 bytes): 88 2f cd 15 17 e8 7e 75 20 20 20 20 20 20 20 20 20 75 65 07 f4 f1 fd 29 1f c7 db cc 81 ce 10 40 5b f6 8e 2f b1 9f dd ef 18 7a 01 e1 df 42 b3 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb 28 b2 e2 36 57 fa b0 b6 80 bf fb 7e ae 92 24 24 ee 10 f4 27 31 9a 11 23 -[2026-02-20T18:22:02.370342] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:02.370364] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:02.370407] LOG: [RX PARSE] RAW Packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:02.370419] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:02.370424] LOG: [RX PARSE] Path length offset: 1, Path length: 23 -[2026-02-20T18:22:02.370443] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=23, firstHop=0xe8, lastHop=0xcc, SNR=11.75, RSSI=-51, payload=75 bytes -[2026-02-20T18:22:02.370450] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=23 -[2026-02-20T18:22:02.370455] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:02.370462] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:02.370500] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:02.370509] LOG: [RX FILTER] Raw packet (100 bytes): 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:02.370612] LOG: [RX FILTER] Header: 0x15 | PathLength: 23 | SNR: 11.75 -[2026-02-20T18:22:02.370620] LOG: [RX FILTER] ✓ RSSI OK (-51 < -30) -[2026-02-20T18:22:02.370625] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:02.370648] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:02.370666] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:02.370743] LOG: [RX FILTER] Encrypted message: 72 bytes -[2026-02-20T18:22:02.370752] LOG: [CRYPTO] Decrypting message (72 bytes) -[2026-02-20T18:22:02.370890] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:02.370944] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:02.371054] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:02.371114] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:02.371122] LOG: [RX LOG] Dropped packet hex: 15 17 E8 7E 75 20 20 20 20 20 20 20 20 20 75 65 07 F4 F1 FD 29 1F C7 DB CC 81 CE 10 40 5B F6 8E 2F B1 9F DD EF 18 7A 01 E1 DF 42 B3 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB 28 B2 E2 36 57 FA B0 B6 80 BF FB 7E AE 92 24 24 EE 10 F4 27 31 9A 11 23 -[2026-02-20T18:22:02.604310] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:02.714939] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff cd 2f 11 00 00 00 a2 23 00 00 -[2026-02-20T18:22:02.715101] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:02.715122] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:22:03.754989] LOG: [GPS SERVICE] Position stream fired: lat=47.36804, lon=-122.07333, accuracy=3.9m -[2026-02-20T18:22:05.009841] LOG: [CONN] Frame received (33 bytes): 88 19 a3 01 08 f2 f5 56 ab 5a 7a 7e 02 f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc -[2026-02-20T18:22:05.009968] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:05.010046] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:05.010083] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.010094] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:22:05.010107] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:05.010130] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0x02, SNR=6.25, RSSI=-93, payload=20 bytes -[2026-02-20T18:22:05.010145] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 -[2026-02-20T18:22:05.010153] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:05.010161] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:05.010192] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:05.010205] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.010217] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 6.25 -[2026-02-20T18:22:05.010232] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) -[2026-02-20T18:22:05.010243] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:22:05.010279] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:05.010288] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E 02 F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.045005] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:22:05.045130] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:22:05.045148] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:22:05.045190] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:22:05.045237] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36804, -122.07333 [0.3w]" -[2026-02-20T18:22:05.045250] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:22:05.045265] LOG: [TX LOG] Payload: "@[MapperBot] 47.36804, -122.07333 [0.3w]" -[2026-02-20T18:22:05.045279] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:22:05.045292] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:22:05.045310] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:22:05.045321] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:22:05.045356] LOG: [CONN] Sending ping: @[MapperBot] 47.36804, -122.07333 [0.3w] -[2026-02-20T18:22:05.301375] LOG: [CONN] Frame received (33 bytes): 88 2f ce 01 08 f2 f5 56 ab 5a 7a 7e cc f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc -[2026-02-20T18:22:05.301514] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:05.301669] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:05.301737] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.301752] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:22:05.301769] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:05.301790] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0xcc, SNR=11.75, RSSI=-50, payload=20 bytes -[2026-02-20T18:22:05.301808] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 -[2026-02-20T18:22:05.301818] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:22:05.301830] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-50 -[2026-02-20T18:22:05.301847] LOG: [TX LOG] Ignoring: header validation failed (header=0x01) -[2026-02-20T18:22:05.301860] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:05.301874] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:05.301913] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:05.301925] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.301943] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 11.75 -[2026-02-20T18:22:05.301958] LOG: [RX FILTER] ✓ RSSI OK (-50 < -30) -[2026-02-20T18:22:05.301970] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:22:05.302014] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:05.302027] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.322405] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:22:05.322505] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:22:05.322598] LOG: [CONN] Received OK response -[2026-02-20T18:22:05.867546] LOG: [CONN] Frame received (33 bytes): 88 2f ab 01 08 f2 f5 56 ab 5a 7a 7e db f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c cc a7 1f fc -[2026-02-20T18:22:05.867690] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:05.867732] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:05.867797] LOG: [RX PARSE] RAW Packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.867811] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:22:05.867822] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:05.867850] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=8, firstHop=0xf2, lastHop=0xdb, SNR=11.75, RSSI=-85, payload=20 bytes -[2026-02-20T18:22:05.867863] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=8 -[2026-02-20T18:22:05.867878] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:22:05.867891] LOG: [TX LOG] Processing rx_log entry: SNR=11.75, RSSI=-85 -[2026-02-20T18:22:05.867902] LOG: [TX LOG] Ignoring: header validation failed (header=0x01) -[2026-02-20T18:22:05.867919] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:05.867929] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:05.867966] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:05.867984] LOG: [RX FILTER] Raw packet (30 bytes): 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:05.867998] LOG: [RX FILTER] Header: 0x01 | PathLength: 8 | SNR: 11.75 -[2026-02-20T18:22:05.868016] LOG: [RX FILTER] ✓ RSSI OK (-85 < -30) -[2026-02-20T18:22:05.868031] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:22:05.868072] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:05.868089] LOG: [RX LOG] Dropped packet hex: 01 08 F2 F5 56 AB 5A 7A 7E DB F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C CC A7 1F FC -[2026-02-20T18:22:07.573739] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:22:07.573865] LOG: [API QUEUE] Item 1/3: type=RX, external_antenna=true -[2026-02-20T18:22:07.573881] LOG: [API QUEUE] Item 2/3: type=RX, external_antenna=true -[2026-02-20T18:22:07.573898] LOG: [API QUEUE] Item 3/3: type=RX, external_antenna=true -[2026-02-20T18:22:07.573908] LOG: [API QUEUE] Uploading 3 items... -[2026-02-20T18:22:07.605056] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:07.724065] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ab 2f 11 00 00 00 a3 23 00 00 -[2026-02-20T18:22:07.724208] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:07.724228] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:22:08.008587] LOG: [GPS SERVICE] Position stream fired: lat=47.36830, lon=-122.07310, accuracy=3.8m -[2026-02-20T18:22:08.034751] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:22:08.034791] LOG: [API] Request: {"data":"3 items","items":"RX:external_antenna=true, RX:external_antenna=true, RX:external_antenna=true"} -[2026-02-20T18:22:08.034799] LOG: [API] Response (200) in 0.46s: {"success":true,"expires_at":1771640827} -[2026-02-20T18:22:08.034804] LOG: [HEARTBEAT] Scheduling in 239s (session expires in 299s) -[2026-02-20T18:22:08.034813] LOG: [API] Upload batch SUCCESS: 3 items -[2026-02-20T18:22:08.037386] LOG: [API QUEUE] Upload SUCCESS: deleted 3 items -[2026-02-20T18:22:08.037404] LOG: [APP] Upload success: +3 items (total: 77) -[2026-02-20T18:22:08.324294] LOG: [PING] Ping sent successfully -[2026-02-20T18:22:10.045942] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:22:10.070459] LOG: [CONN] Frame received (51 bytes): 88 30 cb 21 0a 07 1b ab 50 5a 15 e0 7a 7e cc 2b f4 ef 98 16 4c 7a af fc e6 fd ea 00 94 51 26 ec 3b d6 a0 74 78 31 21 ff 0b 87 d6 43 9b 23 5b 62 64 7f ca -[2026-02-20T18:22:10.070643] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:10.070668] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:10.070717] LOG: [RX PARSE] RAW Packet (48 bytes): 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:10.070732] LOG: [RX PARSE] Header: 0x21, Route type: 1 -[2026-02-20T18:22:10.070741] LOG: [RX PARSE] Path length offset: 1, Path length: 10 -[2026-02-20T18:22:10.070769] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=10, firstHop=0x07, lastHop=0xcc, SNR=12.0, RSSI=-53, payload=36 bytes -[2026-02-20T18:22:10.070781] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=10 -[2026-02-20T18:22:10.070789] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:10.070802] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:10.070840] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:10.070849] LOG: [RX FILTER] Raw packet (48 bytes): 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:10.070866] LOG: [RX FILTER] Header: 0x21 | PathLength: 10 | SNR: 12.0 -[2026-02-20T18:22:10.070877] LOG: [RX FILTER] ✓ RSSI OK (-53 < -30) -[2026-02-20T18:22:10.070890] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x21) -[2026-02-20T18:22:10.070933] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:10.070946] LOG: [RX LOG] Dropped packet hex: 21 0A 07 1B AB 50 5A 15 E0 7A 7E CC 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:11.030068] LOG: [CONN] Frame received (52 bytes): 88 2f ae 21 0b 07 1b ab 50 5a 15 e0 7a 7e 6c db 2b f4 ef 98 16 4c 7a af fc e6 fd ea 00 94 51 26 ec 3b d6 a0 74 78 31 21 ff 0b 87 d6 43 9b 23 5b 62 64 7f ca -[2026-02-20T18:22:11.030160] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:11.030177] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:11.030204] LOG: [RX PARSE] RAW Packet (49 bytes): 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:11.030210] LOG: [RX PARSE] Header: 0x21, Route type: 1 -[2026-02-20T18:22:11.030219] LOG: [RX PARSE] Path length offset: 1, Path length: 11 -[2026-02-20T18:22:11.030236] LOG: [RX PARSE] Parsed metadata: header=0x21, pathLength=11, firstHop=0x07, lastHop=0xdb, SNR=11.75, RSSI=-82, payload=36 bytes -[2026-02-20T18:22:11.030248] LOG: [UNIFIED RX] Packet received: header=0x21, pathLength=11 -[2026-02-20T18:22:11.030252] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:11.030256] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:11.030281] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:11.030286] LOG: [RX FILTER] Raw packet (49 bytes): 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:11.030296] LOG: [RX FILTER] Header: 0x21 | PathLength: 11 | SNR: 11.75 -[2026-02-20T18:22:11.030303] LOG: [RX FILTER] ✓ RSSI OK (-82 < -30) -[2026-02-20T18:22:11.030308] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x21) -[2026-02-20T18:22:11.030335] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:11.030343] LOG: [RX LOG] Dropped packet hex: 21 0B 07 1B AB 50 5A 15 E0 7A 7E 6C DB 2B F4 EF 98 16 4C 7A AF FC E6 FD EA 00 94 51 26 EC 3B D6 A0 74 78 31 21 FF 0B 87 D6 43 9B 23 5B 62 64 7F CA -[2026-02-20T18:22:12.603050] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:12.762865] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff ae 2f 11 00 00 00 a3 23 00 00 -[2026-02-20T18:22:12.763016] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:12.763044] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:22:13.039954] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:22:13.326165] LOG: [PING] RX listening window ended -[2026-02-20T18:22:13.326211] LOG: [PING] No repeater echoes detected during listening window -[2026-02-20T18:22:13.326229] LOG: [GRAPH] Recorded txFail event at -118dBm -[2026-02-20T18:22:13.326266] LOG: [PING] Queued TX entry with heard_repeats: None -[2026-02-20T18:22:13.326272] LOG: [ACTIVE MODE] Scheduling next auto ping after RX window completion -[2026-02-20T18:22:13.326280] LOG: [ACTIVE MODE] Scheduling next auto ping in 30000ms -[2026-02-20T18:22:13.326293] LOG: [ACTIVE MODE] New timer scheduled -[2026-02-20T18:22:13.326299] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:22:13.328337] LOG: [API QUEUE] TX enqueued: None (queue size: 1) -[2026-02-20T18:22:15.014084] LOG: [GPS SERVICE] Position stream fired: lat=47.36845, lon=-122.07288, accuracy=3.8m -[2026-02-20T18:22:15.047695] LOG: [CONN] Frame received (39 bytes): 88 2d b4 01 12 f2 f5 56 ab 5a 7a 7e 75 20 20 20 53 fc 7a 86 e8 7e 6c f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c -[2026-02-20T18:22:15.047753] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:15.047765] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:15.047776] LOG: [RX PARSE] RAW Packet (36 bytes): 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:15.047780] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:22:15.047783] LOG: [RX PARSE] Path length offset: 1, Path length: 18 -[2026-02-20T18:22:15.047794] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=18, firstHop=0xf2, lastHop=0x6c, SNR=11.25, RSSI=-76, payload=16 bytes -[2026-02-20T18:22:15.047798] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=18 -[2026-02-20T18:22:15.047800] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:15.047803] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:15.047812] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:15.047815] LOG: [RX FILTER] Raw packet (36 bytes): 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:15.047820] LOG: [RX FILTER] Header: 0x01 | PathLength: 18 | SNR: 11.25 -[2026-02-20T18:22:15.047824] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) -[2026-02-20T18:22:15.047828] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:22:15.047839] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:15.047842] LOG: [RX LOG] Dropped packet hex: 01 12 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:15.749402] LOG: [CONN] Frame received (40 bytes): 88 30 c8 01 13 f2 f5 56 ab 5a 7a 7e 75 20 20 20 53 fc 7a 86 e8 7e 6c cc f4 2b 19 03 a9 94 24 ce 64 b2 b4 b0 1c 16 5f 2c -[2026-02-20T18:22:15.749523] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:15.749558] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:15.749600] LOG: [RX PARSE] RAW Packet (37 bytes): 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:15.749610] LOG: [RX PARSE] Header: 0x01, Route type: 1 -[2026-02-20T18:22:15.749619] LOG: [RX PARSE] Path length offset: 1, Path length: 19 -[2026-02-20T18:22:15.749652] LOG: [RX PARSE] Parsed metadata: header=0x01, pathLength=19, firstHop=0xf2, lastHop=0xcc, SNR=12.0, RSSI=-56, payload=16 bytes -[2026-02-20T18:22:15.749660] LOG: [UNIFIED RX] Packet received: header=0x1, pathLength=19 -[2026-02-20T18:22:15.749673] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:15.749682] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:15.749711] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:15.750134] LOG: [RX FILTER] Raw packet (37 bytes): 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:15.750155] LOG: [RX FILTER] Header: 0x01 | PathLength: 19 | SNR: 12.0 -[2026-02-20T18:22:15.750169] LOG: [RX FILTER] ✓ RSSI OK (-56 < -30) -[2026-02-20T18:22:15.750195] LOG: [RX FILTER] ❌ DROPPED: unsupported ptype (header=0x01) -[2026-02-20T18:22:15.750256] LOG: [RX LOG] ❌ Packet dropped: unsupported ptype -[2026-02-20T18:22:15.750270] LOG: [RX LOG] Dropped packet hex: 01 13 F2 F5 56 AB 5A 7A 7E 75 20 20 20 53 FC 7A 86 E8 7E 6C CC F4 2B 19 03 A9 94 24 CE 64 B2 B4 B0 1C 16 5F 2C -[2026-02-20T18:22:17.602979] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:17.745032] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff c8 30 11 00 00 00 a4 23 00 00 -[2026-02-20T18:22:17.745169] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:17.745188] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:22:18.329038] LOG: [API QUEUE] Ping flush timer fired -[2026-02-20T18:22:18.329303] LOG: [API QUEUE] Item 1/1: type=TX, external_antenna=true -[2026-02-20T18:22:18.329320] LOG: [API QUEUE] Uploading 1 items... -[2026-02-20T18:22:18.633612] LOG: [API] POST /wardrive-api.php/wardrive -[2026-02-20T18:22:18.633688] LOG: [API] Request: {"data":"1 items","items":"TX:external_antenna=true"} -[2026-02-20T18:22:18.633697] LOG: [API] Response (200) in 0.30s: {"success":true,"expires_at":1771640838} -[2026-02-20T18:22:18.633704] LOG: [HEARTBEAT] Scheduling in 240s (session expires in 300s) -[2026-02-20T18:22:18.633713] LOG: [API] Upload batch SUCCESS: 1 items -[2026-02-20T18:22:18.633955] LOG: [API QUEUE] Upload SUCCESS: deleted 1 items -[2026-02-20T18:22:18.633964] LOG: [APP] Upload success: +1 items (total: 78) -[2026-02-20T18:22:20.701500] LOG: [CONN] Frame received (91 bytes): 88 2d ac 15 03 e8 7e db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df -[2026-02-20T18:22:20.701653] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:20.701686] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:20.701732] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:20.701751] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:20.701755] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:22:20.701784] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xdb, SNR=11.25, RSSI=-84, payload=83 bytes -[2026-02-20T18:22:20.701812] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:22:20.701825] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:20.701838] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:20.701893] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:20.701903] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:20.701925] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 -[2026-02-20T18:22:20.701936] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) -[2026-02-20T18:22:20.701941] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:20.701945] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:20.701956] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:20.701964] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:22:20.701967] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:22:20.702069] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:22:20.702657] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." -[2026-02-20T18:22:20.702703] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:22:20.702710] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:22:20.702787] LOG: [RX LOG] Packet heard via last hop: DB, SNR=11.25, path_length=3 -[2026-02-20T18:22:20.702796] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:22:20.702847] LOG: [RX BATCH] First observation for repeater DB: SNR=11.25 -[2026-02-20T18:22:20.702884] LOG: [RX BATCH] Started 30s timeout timer for repeater DB -[2026-02-20T18:22:20.702948] LOG: [RX BATCH] Distance check for repeater DB: 0.00m from first observation (threshold=25m) -[2026-02-20T18:22:20.702980] LOG: [APP] Immediate RX observation: repeater=DB, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:20.703020] LOG: [APP] Current batch tracking: 0 repeaters: {} -[2026-02-20T18:22:20.703054] LOG: [APP] Created IMMEDIATE RX pin for repeater: DB at 47.36845,-122.07288 (batch tracking: 1 repeaters, rxCount: 43) -[2026-02-20T18:22:20.703099] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:22:20.703133] LOG: [RX LOG] ✅ Observation kept in batch: repeater=DB, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:20.703995] LOG: [CONN] Frame received (1 bytes): 83 -[2026-02-20T18:22:20.704025] LOG: [CONN] Response code: 0x83 (131) -[2026-02-20T18:22:20.704043] LOG: [CONN] Unhandled frame: code=131 (0x83) -[2026-02-20T18:22:21.077843] LOG: [CONN] Frame received (91 bytes): 88 2d a2 15 03 e8 7e ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df -[2026-02-20T18:22:21.077918] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:21.077934] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:21.077961] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.077968] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:21.077973] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:22:21.077982] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0xef, SNR=11.25, RSSI=-94, payload=83 bytes -[2026-02-20T18:22:21.077988] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:22:21.077991] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:21.077993] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:21.078021] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:21.078025] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.078033] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.25 -[2026-02-20T18:22:21.078039] LOG: [RX FILTER] ✓ RSSI OK (-94 < -30) -[2026-02-20T18:22:21.078044] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:21.078051] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:21.078056] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:21.078062] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:22:21.078068] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:22:21.078103] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:22:21.078187] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." -[2026-02-20T18:22:21.078199] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:22:21.078202] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:22:21.078215] LOG: [RX LOG] Packet heard via last hop: EF, SNR=11.25, path_length=3 -[2026-02-20T18:22:21.078218] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:22:21.078227] LOG: [RX BATCH] First observation for repeater EF: SNR=11.25 -[2026-02-20T18:22:21.078233] LOG: [RX BATCH] Started 30s timeout timer for repeater EF -[2026-02-20T18:22:21.078239] LOG: [RX BATCH] Distance check for repeater EF: 0.00m from first observation (threshold=25m) -[2026-02-20T18:22:21.078250] LOG: [APP] Immediate RX observation: repeater=EF, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:21.078257] LOG: [APP] Current batch tracking: 1 repeaters: {DB} -[2026-02-20T18:22:21.078267] LOG: [APP] Created IMMEDIATE RX pin for repeater: EF at 47.36845,-122.07288 (batch tracking: 2 repeaters, rxCount: 44) -[2026-02-20T18:22:21.078275] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:22:21.078284] LOG: [RX LOG] ✅ Observation kept in batch: repeater=EF, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:21.358883] LOG: [CONN] Frame received (91 bytes): 88 30 b4 15 03 e8 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df -[2026-02-20T18:22:21.358907] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:21.358923] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:21.358945] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.358953] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:21.358957] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:22:21.358967] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x6c, SNR=12.0, RSSI=-76, payload=83 bytes -[2026-02-20T18:22:21.358971] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:22:21.358976] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:21.358980] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:21.359] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:21.359006] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.359012] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 12.0 -[2026-02-20T18:22:21.359019] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) -[2026-02-20T18:22:21.359024] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:21.359027] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:21.359034] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:21.359038] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:22:21.359043] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:22:21.359077] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:22:21.359142] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." -[2026-02-20T18:22:21.359150] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:22:21.359157] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:22:21.359205] LOG: [RX LOG] Packet heard via last hop: 6C, SNR=12.0, path_length=3 -[2026-02-20T18:22:21.359208] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:22:21.359213] LOG: [RX BATCH] First observation for repeater 6C: SNR=12.0 -[2026-02-20T18:22:21.359221] LOG: [RX BATCH] Started 30s timeout timer for repeater 6C -[2026-02-20T18:22:21.359227] LOG: [RX BATCH] Distance check for repeater 6C: 0.00m from first observation (threshold=25m) -[2026-02-20T18:22:21.359234] LOG: [APP] Immediate RX observation: repeater=6C, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:21.359450] LOG: [APP] Current batch tracking: 2 repeaters: {DB, EF} -[2026-02-20T18:22:21.359461] LOG: [APP] Created IMMEDIATE RX pin for repeater: 6C at 47.36845,-122.07288 (batch tracking: 3 repeaters, rxCount: 45) -[2026-02-20T18:22:21.359469] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:22:21.359475] LOG: [RX LOG] ✅ Observation kept in batch: repeater=6C, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:21.688232] LOG: [CONN] Frame received (91 bytes): 88 2f b4 15 03 e8 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df -[2026-02-20T18:22:21.688299] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:21.688311] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:21.688335] LOG: [RX PARSE] RAW Packet (88 bytes): 15 03 E8 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.688344] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:21.688347] LOG: [RX PARSE] Path length offset: 1, Path length: 3 -[2026-02-20T18:22:21.688358] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=3, firstHop=0xe8, lastHop=0x02, SNR=11.75, RSSI=-76, payload=83 bytes -[2026-02-20T18:22:21.688363] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=3 -[2026-02-20T18:22:21.688367] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:21.688372] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:21.688393] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:21.688398] LOG: [RX FILTER] Raw packet (88 bytes): 15 03 E8 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:21.688406] LOG: [RX FILTER] Header: 0x15 | PathLength: 3 | SNR: 11.75 -[2026-02-20T18:22:21.688412] LOG: [RX FILTER] ✓ RSSI OK (-76 < -30) -[2026-02-20T18:22:21.688416] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:21.688419] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:21.688424] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:21.688429] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:22:21.688432] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:22:21.688465] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:22:21.688486] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." -[2026-02-20T18:22:21.688496] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:22:21.688498] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:22:21.688510] LOG: [RX LOG] Packet heard via last hop: 02, SNR=11.75, path_length=3 -[2026-02-20T18:22:21.688513] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:22:21.688521] LOG: [RX BATCH] First observation for repeater 02: SNR=11.75 -[2026-02-20T18:22:21.688527] LOG: [RX BATCH] Started 30s timeout timer for repeater 02 -[2026-02-20T18:22:21.688536] LOG: [RX BATCH] Distance check for repeater 02: 0.00m from first observation (threshold=25m) -[2026-02-20T18:22:21.688544] LOG: [APP] Immediate RX observation: repeater=02, snr=11.75, location=47.36845,-122.07288 -[2026-02-20T18:22:21.688552] LOG: [APP] Current batch tracking: 3 repeaters: {DB, EF, 6C} -[2026-02-20T18:22:21.688558] LOG: [APP] Created IMMEDIATE RX pin for repeater: 02 at 47.36845,-122.07288 (batch tracking: 4 repeaters, rxCount: 46) -[2026-02-20T18:22:21.688571] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:22:21.688579] LOG: [RX LOG] ✅ Observation kept in batch: repeater=02, snr=11.75, location=47.36845,-122.07288 -[2026-02-20T18:22:22.005033] LOG: [CONN] Frame received (92 bytes): 88 30 c9 15 04 e8 7e db cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d df -[2026-02-20T18:22:22.005103] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:22.005115] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:22.005139] LOG: [RX PARSE] RAW Packet (89 bytes): 15 04 E8 7E DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:22.005147] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:22.005150] LOG: [RX PARSE] Path length offset: 1, Path length: 4 -[2026-02-20T18:22:22.005162] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=4, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-55, payload=83 bytes -[2026-02-20T18:22:22.005165] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=4 -[2026-02-20T18:22:22.005171] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:22.005175] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:22.005196] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:22.005202] LOG: [RX FILTER] Raw packet (89 bytes): 15 04 E8 7E DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D DF -[2026-02-20T18:22:22.005208] LOG: [RX FILTER] Header: 0x15 | PathLength: 4 | SNR: 12.0 -[2026-02-20T18:22:22.005216] LOG: [RX FILTER] ✓ RSSI OK (-55 < -30) -[2026-02-20T18:22:22.005220] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:22.005223] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:22.005230] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:22.005234] LOG: [RX FILTER] Encrypted message: 80 bytes -[2026-02-20T18:22:22.005242] LOG: [CRYPTO] Decrypting message (80 bytes) -[2026-02-20T18:22:22.005273] LOG: [CRYPTO] Decrypted successfully (80 bytes) -[2026-02-20T18:22:22.005350] LOG: [RX FILTER] Decrypted message (69 chars): "VM Heights War Driver : @[MapperBot] 47.33641, -122.51750 [..." -[2026-02-20T18:22:22.005358] LOG: [RX FILTER] Printable ratio: 94.2% (threshold: 60.0%) -[2026-02-20T18:22:22.005363] LOG: [RX FILTER] ✅ KEPT: GRP_TXT passed all validations -[2026-02-20T18:22:22.005373] LOG: [RX LOG] Packet heard via last hop: CC, SNR=12.0, path_length=4 -[2026-02-20T18:22:22.005378] LOG: [RX LOG] ✅ Packet validated and passed filter -[2026-02-20T18:22:22.005385] LOG: [RX BATCH] First observation for repeater CC: SNR=12.0 -[2026-02-20T18:22:22.005393] LOG: [RX BATCH] Started 30s timeout timer for repeater CC -[2026-02-20T18:22:22.005402] LOG: [RX BATCH] Distance check for repeater CC: 0.00m from first observation (threshold=25m) -[2026-02-20T18:22:22.005409] LOG: [APP] Immediate RX observation: repeater=CC, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:22.005416] LOG: [APP] Current batch tracking: 4 repeaters: {DB, EF, 6C, 02} -[2026-02-20T18:22:22.005426] LOG: [APP] Created IMMEDIATE RX pin for repeater: CC at 47.36845,-122.07288 (batch tracking: 5 repeaters, rxCount: 47) -[2026-02-20T18:22:22.005433] LOG: [GRAPH] Recorded rx event at -119dBm with 1 repeater(s) -[2026-02-20T18:22:22.005441] LOG: [RX LOG] ✅ Observation kept in batch: repeater=CC, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:22.573639] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:22:22.573732] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:22:22.602628] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:22.662658] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff c9 30 11 00 00 00 a5 23 00 00 -[2026-02-20T18:22:22.662720] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:22.662731] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:22:23.634634] LOG: [MAP] Refreshing overlay tiles -[2026-02-20T18:22:25.304015] LOG: [CONN] Frame received (95 bytes): 88 2d a3 15 08 e8 7e 75 20 20 75 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d -[2026-02-20T18:22:25.304095] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:25.304110] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:25.304134] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:25.304141] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:25.304145] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:25.304153] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0x6c, SNR=11.25, RSSI=-93, payload=82 bytes -[2026-02-20T18:22:25.304158] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:22:25.304161] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:25.304165] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:25.304187] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:25.304190] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:25.304210] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 11.25 -[2026-02-20T18:22:25.304215] LOG: [RX FILTER] ✓ RSSI OK (-93 < -30) -[2026-02-20T18:22:25.304219] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:25.304223] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:25.304226] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:25.304231] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:22:25.304234] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:22:25.304315] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:25.304333] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:25.304414] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:25.304451] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:25.304456] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:25.579469] LOG: [CONN] Frame received (95 bytes): 88 31 bc 15 08 e8 7e 75 20 20 75 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d -[2026-02-20T18:22:25.579555] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:25.579573] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:25.579598] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:25.579605] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:25.579609] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:25.579628] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0x02, SNR=12.25, RSSI=-68, payload=82 bytes -[2026-02-20T18:22:25.579633] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:22:25.579636] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:25.579642] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:25.579667] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:25.579670] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:25.579678] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.25 -[2026-02-20T18:22:25.579686] LOG: [RX FILTER] ✓ RSSI OK (-68 < -30) -[2026-02-20T18:22:25.579690] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:25.579693] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:25.579699] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:25.579703] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:22:25.579706] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:22:25.579805] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:25.579825] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:25.579907] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:25.579947] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:25.579951] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.009730] LOG: [GPS SERVICE] Position stream fired: lat=47.36856, lon=-122.07275, accuracy=3.8m -[2026-02-20T18:22:26.009826] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:22:26.009848] LOG: [RX BATCH] Checking 5 active batch(es) for distance trigger -[2026-02-20T18:22:26.009860] LOG: [RX BATCH] Distance check for repeater DB: 16.31m from first observation (threshold=25m) -[2026-02-20T18:22:26.009865] LOG: [RX BATCH] Distance check for repeater EF: 16.31m from first observation (threshold=25m) -[2026-02-20T18:22:26.009888] LOG: [RX BATCH] Distance check for repeater 6C: 16.31m from first observation (threshold=25m) -[2026-02-20T18:22:26.009893] LOG: [RX BATCH] Distance check for repeater 02: 16.31m from first observation (threshold=25m) -[2026-02-20T18:22:26.009899] LOG: [RX BATCH] Distance check for repeater CC: 16.31m from first observation (threshold=25m) -[2026-02-20T18:22:26.009906] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:22:26.202046] LOG: [CONN] Frame received (95 bytes): 88 30 ac 15 08 e8 7e 75 20 20 75 7e db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d -[2026-02-20T18:22:26.202110] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:26.202124] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:26.202147] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.202157] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:26.202160] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:26.202170] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xdb, SNR=12.0, RSSI=-84, payload=82 bytes -[2026-02-20T18:22:26.202174] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:22:26.202177] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:26.202182] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:26.202204] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:26.202207] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.202215] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.0 -[2026-02-20T18:22:26.202221] LOG: [RX FILTER] ✓ RSSI OK (-84 < -30) -[2026-02-20T18:22:26.202225] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:26.202228] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:26.202231] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:26.202237] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:22:26.202240] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:22:26.202308] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:26.202325] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:26.202403] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:26.202439] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:26.202443] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.598291] LOG: [CONN] Frame received (95 bytes): 88 30 c7 15 08 e8 7e 75 20 20 75 7e cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d -[2026-02-20T18:22:26.598316] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:26.598333] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:26.598355] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.598362] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:26.598366] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:26.598374] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xcc, SNR=12.0, RSSI=-57, payload=82 bytes -[2026-02-20T18:22:26.598380] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:22:26.598383] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:26.598387] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:26.598413] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:26.598416] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:26.598423] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 12.0 -[2026-02-20T18:22:26.598427] LOG: [RX FILTER] ✓ RSSI OK (-57 < -30) -[2026-02-20T18:22:26.598432] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:26.598437] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:26.598440] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:26.598445] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:22:26.598450] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:22:26.598538] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:26.598597] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:26.598669] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:26.598719] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:26.598725] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:27.221806] LOG: [CONN] Frame received (95 bytes): 88 2f a6 15 08 e8 7e 75 20 20 75 7e ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 0d -[2026-02-20T18:22:27.221878] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:27.221894] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:27.221920] LOG: [RX PARSE] RAW Packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:27.221927] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:27.221930] LOG: [RX PARSE] Path length offset: 1, Path length: 8 -[2026-02-20T18:22:27.221941] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=8, firstHop=0xe8, lastHop=0xef, SNR=11.75, RSSI=-90, payload=82 bytes -[2026-02-20T18:22:27.221946] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=8 -[2026-02-20T18:22:27.221949] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:27.221954] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:27.221976] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:27.221979] LOG: [RX FILTER] Raw packet (92 bytes): 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:27.221989] LOG: [RX FILTER] Header: 0x15 | PathLength: 8 | SNR: 11.75 -[2026-02-20T18:22:27.221995] LOG: [RX FILTER] ✓ RSSI OK (-90 < -30) -[2026-02-20T18:22:27.222] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:27.222003] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:27.222007] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:27.222014] LOG: [RX FILTER] Encrypted message: 79 bytes -[2026-02-20T18:22:27.222018] LOG: [CRYPTO] Decrypting message (79 bytes) -[2026-02-20T18:22:27.222097] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:27.222116] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:27.222206] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:27.222242] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:27.222248] LOG: [RX LOG] Dropped packet hex: 15 08 E8 7E 75 20 20 75 7E EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 0D -[2026-02-20T18:22:27.602631] LOG: [CONN] ⚡ Fetching battery voltage (poll triggered)... -[2026-02-20T18:22:27.602726] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:27.735993] LOG: [CONN] Frame received (11 bytes): 0c de 0f 41 00 00 00 64 00 00 00 -[2026-02-20T18:22:27.736047] LOG: [CONN] Response code: 0x0c (12) -[2026-02-20T18:22:27.736052] LOG: [CONN] Battery response has 8 extra bytes (ignoring) -[2026-02-20T18:22:27.736060] LOG: [CONN] Battery updated: 4062mV (89%) -[2026-02-20T18:22:27.791318] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff a6 2f 11 00 00 00 a7 23 00 00 -[2026-02-20T18:22:27.791394] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:27.791405] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:22:30.587495] LOG: [CONN] Frame received (98 bytes): 88 2f b1 15 0c e8 7e 75 20 20 20 53 e0 7e 3e 32 db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 -[2026-02-20T18:22:30.587668] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:30.587794] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:30.587823] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:30.587830] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:30.587834] LOG: [RX PARSE] Path length offset: 1, Path length: 12 -[2026-02-20T18:22:30.587845] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=12, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-79, payload=81 bytes -[2026-02-20T18:22:30.587849] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=12 -[2026-02-20T18:22:30.587854] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:30.587858] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:30.587941] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:30.587946] LOG: [RX FILTER] Raw packet (95 bytes): 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:30.587953] LOG: [RX FILTER] Header: 0x15 | PathLength: 12 | SNR: 11.75 -[2026-02-20T18:22:30.587962] LOG: [RX FILTER] ✓ RSSI OK (-79 < -30) -[2026-02-20T18:22:30.587965] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:30.587968] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:30.587974] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:30.587978] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:22:30.587981] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:22:30.588108] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:30.588128] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:30.588206] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:30.588244] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:30.588248] LOG: [RX LOG] Dropped packet hex: 15 0C E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:30.991955] LOG: [CONN] Frame received (99 bytes): 88 30 ba 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 -[2026-02-20T18:22:30.992066] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:30.992092] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:30.992147] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:30.992162] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:30.992169] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:22:30.992192] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0x02, SNR=12.0, RSSI=-70, payload=81 bytes -[2026-02-20T18:22:30.992201] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:22:30.992208] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:30.992217] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:30.992269] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:30.992280] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:30.992295] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 12.0 -[2026-02-20T18:22:30.992308] LOG: [RX FILTER] ✓ RSSI OK (-70 < -30) -[2026-02-20T18:22:30.992315] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:30.992321] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:30.992333] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:30.992342] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:22:30.992348] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:22:30.992477] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:30.992509] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:30.992647] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:30.992731] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:30.992738] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.363647] LOG: [CONN] Frame received (99 bytes): 88 2b a7 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 -[2026-02-20T18:22:31.363690] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:31.363720] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:31.363774] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.363787] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:31.363794] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:22:31.363823] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0x6c, SNR=10.75, RSSI=-89, payload=81 bytes -[2026-02-20T18:22:31.363832] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:22:31.363838] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:31.363847] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:31.363898] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:31.363908] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.363921] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 10.75 -[2026-02-20T18:22:31.363933] LOG: [RX FILTER] ✓ RSSI OK (-89 < -30) -[2026-02-20T18:22:31.363940] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:31.363946] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:31.363955] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:31.363963] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:22:31.363969] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:22:31.364103] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:31.364217] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:31.364381] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:31.364467] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:31.364473] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.791236] LOG: [CONN] Frame received (99 bytes): 88 2f a6 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db ef 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 -[2026-02-20T18:22:31.791350] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:31.791373] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:31.791427] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.791442] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:31.791448] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:22:31.791467] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0xef, SNR=11.75, RSSI=-90, payload=81 bytes -[2026-02-20T18:22:31.791476] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:22:31.791484] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:31.791492] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:31.791547] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:31.791556] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:31.791568] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 11.75 -[2026-02-20T18:22:31.791581] LOG: [RX FILTER] ✓ RSSI OK (-90 < -30) -[2026-02-20T18:22:31.791587] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:31.791601] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:31.791608] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:31.791615] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:22:31.791624] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:22:31.791750] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:31.791781] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:31.791921] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:31.792] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:31.792007] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB EF 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:32.443180] LOG: [CONN] Frame received (99 bytes): 88 2b b7 15 0d e8 7e 75 20 20 20 53 e0 7e 3e 32 db cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 5e a7 -[2026-02-20T18:22:32.443299] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:32.443318] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:32.443357] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:32.443368] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:32.443374] LOG: [RX PARSE] Path length offset: 1, Path length: 13 -[2026-02-20T18:22:32.443389] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=13, firstHop=0xe8, lastHop=0xcc, SNR=10.75, RSSI=-73, payload=81 bytes -[2026-02-20T18:22:32.443397] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=13 -[2026-02-20T18:22:32.443401] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:32.443444] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:32.443481] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:32.443488] LOG: [RX FILTER] Raw packet (96 bytes): 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:32.443498] LOG: [RX FILTER] Header: 0x15 | PathLength: 13 | SNR: 10.75 -[2026-02-20T18:22:32.443508] LOG: [RX FILTER] ✓ RSSI OK (-73 < -30) -[2026-02-20T18:22:32.443513] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:32.443517] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:32.443525] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:32.443531] LOG: [RX FILTER] Encrypted message: 78 bytes -[2026-02-20T18:22:32.443535] LOG: [CRYPTO] Decrypting message (78 bytes) -[2026-02-20T18:22:32.443638] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:32.443661] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:32.443775] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:32.443837] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:32.443842] LOG: [RX LOG] Dropped packet hex: 15 0D E8 7E 75 20 20 20 53 E0 7E 3E 32 DB CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 5E A7 -[2026-02-20T18:22:32.602673] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:32.651258] LOG: [CONN] Frame received (14 bytes): 18 01 88 ff b7 2b 11 00 00 00 a9 23 00 00 -[2026-02-20T18:22:32.651332] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:32.651341] LOG: [CONN] Noise floor updated: -120dBm -[2026-02-20T18:22:34.950719] LOG: [CONN] Frame received (99 bytes): 88 2f a8 15 0f e8 7e 75 20 20 20 20 20 75 ee 66 6a 17 1f db 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 -[2026-02-20T18:22:34.950805] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:34.950823] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:34.950867] LOG: [RX PARSE] RAW Packet (96 bytes): 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:34.950878] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:34.950885] LOG: [RX PARSE] Path length offset: 1, Path length: 15 -[2026-02-20T18:22:34.950897] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=15, firstHop=0xe8, lastHop=0xdb, SNR=11.75, RSSI=-88, payload=79 bytes -[2026-02-20T18:22:34.950906] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=15 -[2026-02-20T18:22:34.950911] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:34.950917] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:34.950975] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:34.950980] LOG: [RX FILTER] Raw packet (96 bytes): 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:34.950991] LOG: [RX FILTER] Header: 0x15 | PathLength: 15 | SNR: 11.75 -[2026-02-20T18:22:34.950998] LOG: [RX FILTER] ✓ RSSI OK (-88 < -30) -[2026-02-20T18:22:34.951007] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:34.951012] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:34.951018] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:34.951028] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:22:34.951032] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:22:34.951179] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:34.951262] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:34.951387] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:34.951454] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:34.951460] LOG: [RX LOG] Dropped packet hex: 15 0F E8 7E 75 20 20 20 20 20 75 EE 66 6A 17 1F DB 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.471704] LOG: [CONN] Frame received (98 bytes): 88 29 b5 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e 02 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 -[2026-02-20T18:22:35.471767] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:35.471781] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:35.471808] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.471815] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:35.471819] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:22:35.471831] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x02, SNR=10.25, RSSI=-75, payload=79 bytes -[2026-02-20T18:22:35.471853] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:22:35.471856] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:35.471861] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:35.471889] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:35.471893] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.471902] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 10.25 -[2026-02-20T18:22:35.471907] LOG: [RX FILTER] ✓ RSSI OK (-75 < -30) -[2026-02-20T18:22:35.471914] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:35.471917] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:35.471920] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:35.471926] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:22:35.471929] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:22:35.472004] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:35.472022] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:35.472106] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:35.472147] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:35.472152] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 02 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.993157] LOG: [CONN] Frame received (98 bytes): 88 32 ab 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e 6c 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 -[2026-02-20T18:22:35.993226] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:35.993238] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:35.993271] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.993279] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:35.993283] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:22:35.993298] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0x6c, SNR=12.5, RSSI=-85, payload=79 bytes -[2026-02-20T18:22:35.993303] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:22:35.993310] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:35.993314] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:35.993344] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:35.993351] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:35.993358] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.5 -[2026-02-20T18:22:35.993366] LOG: [RX FILTER] ✓ RSSI OK (-85 < -30) -[2026-02-20T18:22:35.993370] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:35.993374] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:35.993381] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:35.993386] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:22:35.993389] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:22:35.993466] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:35.993485] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:35.993571] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:35.993617] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:35.993622] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E 6C 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:36.492060] LOG: [CONN] Frame received (98 bytes): 88 31 bc 15 0e e8 7e 75 20 20 20 20 20 75 2b 07 f4 7e cc 81 95 57 cb 05 da 53 5a 3a 76 60 df 52 7a 31 f5 73 16 7e 17 9f db a4 03 bf 53 0b 98 d6 c2 97 e9 df 81 b7 d8 0b 7a 6a 05 7a df 89 0b 22 64 67 5f 92 4c bb d4 b4 d7 84 d9 cd 9f 35 70 73 59 81 b4 74 4d 34 5a 3d 9d 23 e5 81 a5 e7 a8 9c 0e 11 -[2026-02-20T18:22:36.492087] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:36.492106] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:36.492134] LOG: [RX PARSE] RAW Packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:36.492141] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:36.492145] LOG: [RX PARSE] Path length offset: 1, Path length: 14 -[2026-02-20T18:22:36.492154] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=14, firstHop=0xe8, lastHop=0xcc, SNR=12.25, RSSI=-68, payload=79 bytes -[2026-02-20T18:22:36.492172] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=14 -[2026-02-20T18:22:36.492175] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:36.492177] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:36.492204] LOG: [RX FILTER] ========== VALIDATING PACKET ========== -[2026-02-20T18:22:36.492207] LOG: [RX FILTER] Raw packet (95 bytes): 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:36.492215] LOG: [RX FILTER] Header: 0x15 | PathLength: 14 | SNR: 12.25 -[2026-02-20T18:22:36.492219] LOG: [RX FILTER] ✓ RSSI OK (-68 < -30) -[2026-02-20T18:22:36.492224] LOG: [RX FILTER] Packet type: GRP_TXT (0x15) -[2026-02-20T18:22:36.492228] LOG: [RX FILTER] Channel hash: 0x81 -[2026-02-20T18:22:36.492232] LOG: [RX FILTER] ✓ Channel matched: #wardriving -[2026-02-20T18:22:36.492238] LOG: [RX FILTER] Encrypted message: 76 bytes -[2026-02-20T18:22:36.492243] LOG: [CRYPTO] Decrypting message (76 bytes) -[2026-02-20T18:22:36.492317] ERROR: ❌ [CRYPTO] Decryption failed: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:36.492375] ERROR: ❌ [RX FILTER] ❌ Validation error: Invalid argument(s): Input buffer too short -[2026-02-20T18:22:36.492454] ERROR: ❌ [RX FILTER] Stack trace: #0 AESEngine.processBlock (package:pointycastle/block/aes.dart:1325) -#1 ECBBlockCipher.processBlock (package:pointycastle/block/modes/ecb.dart:42) -#2 CryptoService.decryptChannelMessage (package:mesh_mapper/services/meshcore/crypto_service.dart:124) -#3 PacketValidator._validateGroupText (package:mesh_mapper/services/meshcore/packet_validator.dart:104) -#4 PacketValidator.validate (package:mesh_mapper/services/meshcore/packet_validator.dart:58) -#5 RxLogger.handlePacket (package:mesh_mapper/services/meshcore/rx_logger.dart:126) -#6 UnifiedRxHandler.handlePacket (package:mesh_mapper/services/meshcore/unified_rx_handler.dart:89) -#7 AppStateProvider._createUnifiedRxHandler. (package:mesh_mapper/providers/app_state_provider.dart:1719) -#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778) -#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381) -#10 _DelayedData.perform (dart:async/stream_impl.dart:573) -#11 _PendingEvents.handleNext (dart:async/stream_impl.dart:678) -#12 _PendingEvents.schedule. (dart:async/stream_impl.dart:649) -#13 _microtaskLoop (dart:async/schedule_microtask.dart:40) -#14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) - -[2026-02-20T18:22:36.492547] LOG: [RX LOG] ❌ Packet dropped: validation error -[2026-02-20T18:22:36.492553] LOG: [RX LOG] Dropped packet hex: 15 0E E8 7E 75 20 20 20 20 20 75 2B 07 F4 7E CC 81 95 57 CB 05 DA 53 5A 3A 76 60 DF 52 7A 31 F5 73 16 7E 17 9F DB A4 03 BF 53 0B 98 D6 C2 97 E9 DF 81 B7 D8 0B 7A 6A 05 7A DF 89 0B 22 64 67 5F 92 4C BB D4 B4 D7 84 D9 CD 9F 35 70 73 59 81 B4 74 4D 34 5A 3D 9D 23 E5 81 A5 E7 A8 9C 0E 11 -[2026-02-20T18:22:37.574731] LOG: [API QUEUE] Batch timer fired (15s interval) -[2026-02-20T18:22:37.574881] LOG: [API QUEUE] Upload skipped: queue empty -[2026-02-20T18:22:37.602820] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:37.784831] LOG: [CONN] Frame received (14 bytes): 18 01 8a ff bc 31 11 00 00 00 aa 23 00 00 -[2026-02-20T18:22:37.784985] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:37.785006] LOG: [CONN] Noise floor updated: -118dBm -[2026-02-20T18:22:42.602880] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:42.793461] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff bc 31 11 00 00 00 aa 23 00 00 -[2026-02-20T18:22:42.793564] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:42.793583] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:22:43.326973] LOG: [ACTIVE MODE] Auto ping timer fired -[2026-02-20T18:22:43.327149] LOG: [ACTIVE MODE] Sending auto ping -[2026-02-20T18:22:43.327166] LOG: [PING] sendTxPing called (manual=false) -[2026-02-20T18:22:43.327209] LOG: [PING] Created TxPing, ready for echo tracking -[2026-02-20T18:22:43.327270] LOG: [PING] Starting TX echo tracking for: "@[MapperBot] 47.36856, -122.07275 [0.3w]" -[2026-02-20T18:22:43.327280] LOG: [TX LOG] Starting echo tracking -[2026-02-20T18:22:43.327292] LOG: [TX LOG] Payload: "@[MapperBot] 47.36856, -122.07275 [0.3w]" -[2026-02-20T18:22:43.327303] LOG: [TX LOG] Channel: 2, Hash: 0x81 -[2026-02-20T18:22:43.327317] LOG: [TX LOG] Echo tracking window started (5s) -[2026-02-20T18:22:43.327332] LOG: [AUDIO] playTransmitSound called - initialized=true, enabled=false -[2026-02-20T18:22:43.327342] LOG: [AUDIO] playTransmitSound skipped - not initialized or disabled -[2026-02-20T18:22:43.327360] LOG: [CONN] Sending ping: @[MapperBot] 47.36856, -122.07275 [0.3w] -[2026-02-20T18:22:43.451203] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:22:43.451266] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:22:43.451271] LOG: [CONN] Received OK response -[2026-02-20T18:22:44.157633] LOG: [CONN] Frame received (73 bytes): 88 31 ce 15 01 cc 81 ad b5 13 31 c2 c5 a9 1b dc 27 cd 01 62 37 af 6e 29 c2 c9 f6 de 44 d6 aa 36 77 63 ab f0 f7 c0 d4 4e 42 63 5a 16 58 46 8d 99 8f e1 c7 bb 11 b5 9c eb c7 19 55 94 25 e0 39 e7 92 a9 03 64 ee 26 2f 0d b7 -[2026-02-20T18:22:44.157740] LOG: [CONN] Response code: 0x88 (136) -[2026-02-20T18:22:44.157761] LOG: [RX PARSE] Starting metadata parsing -[2026-02-20T18:22:44.157803] LOG: [RX PARSE] RAW Packet (70 bytes): 15 01 CC 81 AD B5 13 31 C2 C5 A9 1B DC 27 CD 01 62 37 AF 6E 29 C2 C9 F6 DE 44 D6 AA 36 77 63 AB F0 F7 C0 D4 4E 42 63 5A 16 58 46 8D 99 8F E1 C7 BB 11 B5 9C EB C7 19 55 94 25 E0 39 E7 92 A9 03 64 EE 26 2F 0D B7 -[2026-02-20T18:22:44.157834] LOG: [RX PARSE] Header: 0x15, Route type: 1 -[2026-02-20T18:22:44.157840] LOG: [RX PARSE] Path length offset: 1, Path length: 1 -[2026-02-20T18:22:44.157920] LOG: [RX PARSE] Parsed metadata: header=0x15, pathLength=1, firstHop=0xcc, lastHop=0xcc, SNR=12.25, RSSI=-50, payload=67 bytes -[2026-02-20T18:22:44.157929] LOG: [UNIFIED RX] Packet received: header=0x15, pathLength=1 -[2026-02-20T18:22:44.157938] LOG: [UNIFIED RX] TX tracking active - checking for echo -[2026-02-20T18:22:44.157946] LOG: [TX LOG] Processing rx_log entry: SNR=12.25, RSSI=-50 -[2026-02-20T18:22:44.157952] LOG: [TX LOG] Header validation passed: 0x15 -[2026-02-20T18:22:44.157961] LOG: [TX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:22:44.157968] LOG: [UNIFIED RX] RX wardriving active - logging observation -[2026-02-20T18:22:44.157973] LOG: [RX LOG] Processing packet for passive logging -[2026-02-20T18:22:44.157983] LOG: [RX LOG] CARpeater pass-through: single-hop, dropping -[2026-02-20T18:22:46.453022] LOG: [PING] Ping sent successfully -[2026-02-20T18:22:47.468786] LOG: [HEARTBEAT] Heartbeat mode disabled -[2026-02-20T18:22:47.468843] LOG: [PING] Force disabling auto-ping -[2026-02-20T18:22:47.468849] LOG: [DISC] Stopping discovery mode -[2026-02-20T18:22:47.471543] LOG: [WAKELOCK] Screen wake lock disabled -[2026-02-20T18:22:47.471663] LOG: [GRAPH] Ended session: 22:48, 273 samples, 82 markers -[2026-02-20T18:22:47.472795] LOG: [BACKGROUND] Stopping background service -[2026-02-20T18:22:47.472844] LOG: [BACKGROUND] Background service stopped -[2026-02-20T18:22:47.472850] LOG: [TIMER] Cooldown timer stopped -[2026-02-20T18:22:47.472853] LOG: [RX LOG] Stopping passive RX wardriving: trigger=disconnect -[2026-02-20T18:22:47.472859] LOG: [RX BATCH] Flushing all repeaters, trigger=disconnect, active_repeaters=5 -[2026-02-20T18:22:47.472867] LOG: [RX BATCH] Flushing repeater DB -[2026-02-20T18:22:47.472870] LOG: [RX BATCH] Cleared timeout timer for repeater DB -[2026-02-20T18:22:47.472880] LOG: [RX BATCH] Posting repeater DB: snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472884] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:22:47.472890] LOG: [APP] Finalized RX entry (best SNR): repeater=DB, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472897] LOG: [APP] RX pin SNR unchanged for repeater=DB: batch best 11.25 <= pin 11.25 -[2026-02-20T18:22:47.472901] LOG: [APP] Cleared batch tracking for DB: wasPresent=true, remaining=4 -[2026-02-20T18:22:47.472907] LOG: [APP] Added RX log entry: repeater=DB, snr=11.25, pathLen=3 -[2026-02-20T18:22:47.472918] LOG: [API QUEUE] Timers stopped on disconnect -[2026-02-20T18:22:47.472924] LOG: [API QUEUE] Clearing 1 items on disconnect (queue: 0, rxBuffer: 1) -[2026-02-20T18:22:47.472931] LOG: [RX BATCH] Repeater DB removed from buffer -[2026-02-20T18:22:47.472934] LOG: [RX BATCH] Flushing repeater EF -[2026-02-20T18:22:47.472938] LOG: [RX BATCH] Cleared timeout timer for repeater EF -[2026-02-20T18:22:47.472943] LOG: [RX BATCH] Posting repeater EF: snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472945] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:22:47.472951] LOG: [APP] Finalized RX entry (best SNR): repeater=EF, snr=11.25, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472955] LOG: [APP] RX pin SNR unchanged for repeater=EF: batch best 11.25 <= pin 11.25 -[2026-02-20T18:22:47.472958] LOG: [APP] Cleared batch tracking for EF: wasPresent=true, remaining=3 -[2026-02-20T18:22:47.472964] LOG: [APP] Added RX log entry: repeater=EF, snr=11.25, pathLen=3 -[2026-02-20T18:22:47.472972] LOG: [RX BATCH] Repeater EF removed from buffer -[2026-02-20T18:22:47.472975] LOG: [RX BATCH] Flushing repeater 6C -[2026-02-20T18:22:47.472977] LOG: [RX BATCH] Cleared timeout timer for repeater 6C -[2026-02-20T18:22:47.472985] LOG: [RX BATCH] Posting repeater 6C: snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472987] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:22:47.472992] LOG: [APP] Finalized RX entry (best SNR): repeater=6C, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:47.472997] LOG: [APP] RX pin SNR unchanged for repeater=6C: batch best 12.00 <= pin 12.00 -[2026-02-20T18:22:47.473] LOG: [APP] Cleared batch tracking for 6C: wasPresent=true, remaining=2 -[2026-02-20T18:22:47.473021] LOG: [APP] Added RX log entry: repeater=6C, snr=12.0, pathLen=3 -[2026-02-20T18:22:47.473042] LOG: [RX BATCH] Repeater 6C removed from buffer -[2026-02-20T18:22:47.473046] LOG: [RX BATCH] Flushing repeater 02 -[2026-02-20T18:22:47.473051] LOG: [RX BATCH] Cleared timeout timer for repeater 02 -[2026-02-20T18:22:47.473055] LOG: [RX BATCH] Posting repeater 02: snr=11.75, location=47.36845,-122.07288 -[2026-02-20T18:22:47.473058] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:22:47.473064] LOG: [APP] Finalized RX entry (best SNR): repeater=02, snr=11.75, location=47.36845,-122.07288 -[2026-02-20T18:22:47.473069] LOG: [APP] RX pin SNR unchanged for repeater=02: batch best 11.75 <= pin 11.75 -[2026-02-20T18:22:47.473074] LOG: [APP] Cleared batch tracking for 02: wasPresent=true, remaining=1 -[2026-02-20T18:22:47.473079] LOG: [APP] Added RX log entry: repeater=02, snr=11.75, pathLen=3 -[2026-02-20T18:22:47.473086] LOG: [RX BATCH] Repeater 02 removed from buffer -[2026-02-20T18:22:47.473089] LOG: [RX BATCH] Flushing repeater CC -[2026-02-20T18:22:47.473094] LOG: [RX BATCH] Cleared timeout timer for repeater CC -[2026-02-20T18:22:47.473098] LOG: [RX BATCH] Posting repeater CC: snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:47.473101] LOG: [APP] ========== BATCH FLUSH CALLBACK ========== -[2026-02-20T18:22:47.473108] LOG: [APP] Finalized RX entry (best SNR): repeater=CC, snr=12.0, location=47.36845,-122.07288 -[2026-02-20T18:22:47.473111] LOG: [APP] RX pin SNR unchanged for repeater=CC: batch best 12.00 <= pin 12.00 -[2026-02-20T18:22:47.473116] LOG: [APP] Cleared batch tracking for CC: wasPresent=true, remaining=0 -[2026-02-20T18:22:47.473121] LOG: [APP] Added RX log entry: repeater=CC, snr=12.0, pathLen=4 -[2026-02-20T18:22:47.473129] LOG: [RX BATCH] Repeater CC removed from buffer -[2026-02-20T18:22:47.473133] LOG: [RX BATCH] All repeaters flushed: 5 total -[2026-02-20T18:22:47.473356] LOG: [APP] Releasing API session -[2026-02-20T18:22:47.602828] LOG: [CONN] Fetching noise floor... -[2026-02-20T18:22:47.654284] LOG: [CONN] Frame received (14 bytes): 18 01 89 ff 97 90 11 00 00 00 aa 23 00 00 -[2026-02-20T18:22:47.654398] LOG: [CONN] Response code: 0x18 (24) -[2026-02-20T18:22:47.654413] LOG: [CONN] Noise floor updated: -119dBm -[2026-02-20T18:22:48.327946] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:22:48.913528] LOG: [API] POST /wardrive-api.php/auth -[2026-02-20T18:22:48.913563] LOG: [API] Request: {"reason":"disconnect"} -[2026-02-20T18:22:48.913570] LOG: [API] Response (200) in 1.44s: {"success":true,"disconnected":true} -[2026-02-20T18:22:48.913575] LOG: [API] Session cleared -[2026-02-20T18:22:48.913579] LOG: [APP] API session released successfully -[2026-02-20T18:22:49.065339] LOG: [CONN] Frame received (1 bytes): 00 -[2026-02-20T18:22:49.065644] LOG: [CONN] Response code: 0x00 (0) -[2026-02-20T18:22:49.065653] LOG: [CONN] Received OK response -[2026-02-20T18:22:49.066297] LOG: [CHANNEL] Deleting channel at index 2 -[2026-02-20T18:22:49.120917] LOG: [CHANNEL] Channel deleted successfully -[2026-02-20T18:22:49.120982] LOG: [UNIFIED RX] Disposing unified handler -[2026-02-20T18:22:49.120986] LOG: [UNIFIED RX] Stopping unified RX listening -[2026-02-20T18:22:49.120992] LOG: [UNIFIED RX] ✅ Unified listening stopped -[2026-02-20T18:22:49.120997] LOG: [TX LOG] Stopping echo tracking (heard 0 repeaters) -[2026-02-20T18:22:49.121] LOG: [RX LOG] Disposing RX Logger -[2026-02-20T18:22:49.122983] LOG: [CONN] Disconnecting -[2026-02-20T18:22:49.122997] LOG: [CONN] Stopped noise floor polling -[2026-02-20T18:22:49.123] LOG: [CONN] Stopped battery polling -[2026-02-20T18:22:49.128674] LOG: [BLE] Connection state changed: BluetoothConnectionState.disconnected -[2026-02-20T18:22:49.128733] LOG: [CONN] Step: ConnectionStep.disconnected -[2026-02-20T18:22:49.128738] LOG: [CONN] Disconnected successfully -[2026-02-20T18:22:49.128749] LOG: [HEARTBEAT] Heartbeat mode disabled -[2026-02-20T18:22:49.128752] LOG: [CONN] Heartbeat disabled due to BLE disconnect -[2026-02-20T18:22:49.128777] LOG: [API QUEUE] Timers stopped on disconnect -[2026-02-20T18:22:49.128790] LOG: [CONN] Stopped noise floor polling -[2026-02-20T18:22:49.128793] LOG: [CONN] Stopped battery polling -[2026-02-20T18:22:49.128799] LOG: [DISC] Stopping discovery mode -[2026-02-20T18:22:49.128920] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:22:49.128935] LOG: [CHANNEL] Clearing regional channels -[2026-02-20T18:22:49.128952] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:22:49.129250] LOG: [APP] Saved preferences -[2026-02-20T18:35:06.841467] LOG: [GPS SERVICE] Position stream fired: lat=47.36841, lon=-122.07247, accuracy=11.4m -[2026-02-20T18:35:06.841540] LOG: [HIVE] Opening box "user_preferences"... -[2026-02-20T18:35:06.841570] LOG: [GEOFENCE] Moved 100m+ while disconnected, rechecking zone -[2026-02-20T18:35:06.841574] LOG: [GEOFENCE] checkZoneStatus() called -[2026-02-20T18:35:06.841588] LOG: [GEOFENCE] Pre-check state: inZone=true, isCheckingZone=false, hasPosition=true, gpsStatus=GpsStatus.locked -[2026-02-20T18:35:06.841599] LOG: [GEOFENCE] Starting zone check - setting isCheckingZone=true (previous inZone=true) -[2026-02-20T18:35:06.841604] LOG: [GEOFENCE] Making API call to check zone at 47.36841, -122.07247 (accuracy: 11.4m) -[2026-02-20T18:35:06.842569] LOG: [HIVE] Box "user_preferences" opened successfully -[2026-02-20T18:35:06.900196] LOG: [APP] App resumed from background -[2026-02-20T18:35:07.201989] LOG: [API] POST /wardrive-api.php/status -[2026-02-20T18:35:07.202025] LOG: [API] Request: {"lat":47.3684066,"lng":-122.0724722,"accuracy_m":11.39900016784668,"ver":"APP-1771555184","timestamp":1771641306} -[2026-02-20T18:35:07.202029] LOG: [API] Response (200) in 0.36s: {"success":true,"in_zone":true,"zone":{"name":"Seattle, US","code":"SEA","enabled":true,"at_capacity":false,"slots_available":14,"slots_max":15}} -[2026-02-20T18:35:07.202036] LOG: [GEOFENCE] API response received: valid -[2026-02-20T18:35:07.202043] LOG: [GEOFENCE] In zone: Seattle, US (SEA) -[2026-02-20T18:35:07.202045] LOG: [MAP] Repeaters already loaded for zone: SEA -[2026-02-20T18:35:07.202051] LOG: [GEOFENCE] Zone check complete - final state: inZone=true, isCheckingZone=false, zoneName=Seattle, US, zoneCode=SEA -[2026-02-20T18:39:04.130110] LOG: [APP] App resumed from background -[2026-02-20T19:21:20.992957] LOG: [APP] App resumed from background -[2026-02-20T19:21:53.358683] LOG: [DEBUG] Rotating log file for upload... - -=== Log rotated for upload: 2026-02-20T19:21:53.358790 === diff --git a/lib/main.dart b/lib/main.dart index f29e80e..49efe51 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,15 +15,14 @@ import 'services/bluetooth/mobile_bluetooth.dart'; import 'services/bluetooth/web_bluetooth.dart'; import 'services/background_service.dart'; import 'services/debug_file_logger.dart'; -import 'utils/constants.dart'; import 'utils/debug_logger_io.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - // Enable debug file logging FIRST on mobile for dev builds + // Enable debug file logging FIRST on mobile to capture early logs // This must happen before DebugLogger.initialize() to capture early logs - if (!kIsWeb && AppConstants.isDevelopmentBuild) { + if (!kIsWeb) { await DebugFileLogger.enable(); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index d7995b7..6205faf 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -452,8 +452,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _rxWindowTimer = RxWindowTimer(onUpdate: notifyListeners); _discoveryWindowTimer = DiscoveryWindowTimer(onUpdate: notifyListeners); - // Auto-enable debug logging for development builds - await _autoEnableDebugLogsIfDevelopmentBuild(); + // Initialize debug logging (enabled by default, respects user preference) + await _initDebugLogs(); // Initialize channel service with Public channel only (regional channels added after auth) await ChannelService.initializePublicChannel(); @@ -3437,21 +3437,38 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Debug File Logging (Mobile Only) // ============================================ - /// Auto-enable debug file logging for development builds - Future _autoEnableDebugLogsIfDevelopmentBuild() async { + /// Initialize debug file logging, respecting persisted user preference. + /// Enabled by default on all builds. If the user previously disabled it, + /// that preference is restored. + Future _initDebugLogs() async { if (kIsWeb) return; // File logging not available on web - if (AppConstants.isDevelopmentBuild) { - debugLog('[INIT] Development build detected (${AppConstants.appVersion}), auto-enabling debug logs'); - try { - await DebugFileLogger.enable(); + try { + final box = await _openBoxSafely(_preferencesBoxName); + if (box == null) { + // Can't read preference — keep default (enabled, already started in main.dart) _debugLogsEnabled = true; await _refreshDebugLogFiles(); - } catch (e) { - debugError('[INIT] Failed to auto-enable debug logs: $e'); + return; } - } else { - debugLog('[INIT] Release build (${AppConstants.appVersion}), debug logs disabled by default'); + + final userDisabled = box.get('debug_logs_enabled') == false; + + if (userDisabled) { + debugLog('[INIT] Debug logs disabled by user preference, turning off'); + await DebugFileLogger.disable(); + _debugLogsEnabled = false; + DebugLogger.setEnabled(false); + } else { + debugLog('[INIT] Debug logging enabled (${AppConstants.appVersion})'); + // DebugFileLogger already enabled in main.dart + _debugLogsEnabled = true; + await _refreshDebugLogFiles(); + } + } catch (e) { + debugError('[INIT] Failed to init debug logs: $e'); + // Fallback: keep enabled (already started in main.dart) + _debugLogsEnabled = true; } } @@ -3468,6 +3485,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _debugLogsEnabled = true; DebugLogger.setEnabled(true); await _refreshDebugLogFiles(); + // Persist user preference + final box = await _openBoxSafely(_preferencesBoxName); + await box?.put('debug_logs_enabled', true); notifyListeners(); debugLog('[DEBUG] Debug file logging enabled'); } catch (e) { @@ -3487,6 +3507,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { await DebugFileLogger.disable(); _debugLogsEnabled = false; DebugLogger.setEnabled(false); + // Persist user preference + final box = await _openBoxSafely(_preferencesBoxName); + await box?.put('debug_logs_enabled', false); notifyListeners(); } catch (e) { debugError('[DEBUG] Failed to disable debug file logging: $e'); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 4337144..9e5cea4 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -689,9 +689,7 @@ class _SettingsScreenState extends State { ), subtitle: Text( appState.debugLogsEnabled - ? AppConstants.isDevelopmentBuild - ? 'Auto-enabled for development build' - : 'Writing logs to file' + ? 'Writing logs to file' : 'Enable to save debug logs to device', ), value: appState.debugLogsEnabled, diff --git a/lib/utils/debug_logger_stub.dart b/lib/utils/debug_logger_stub.dart index b7e96ba..4dc5a98 100644 --- a/lib/utils/debug_logger_stub.dart +++ b/lib/utils/debug_logger_stub.dart @@ -20,8 +20,8 @@ class DebugLogger { if (_initialized) return; _initialized = true; - // On mobile, enable debug logging in debug mode - _debugEnabled = kDebugMode; + // Enable debug logging by default on all builds + _debugEnabled = true; if (_debugEnabled) { debugPrint('[DEBUG] Debug logging ENABLED (debug mode)'); From 22334a479320fbe558fa7cb9205dedd4688c8f02 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Thu, 26 Feb 2026 19:17:28 -0500 Subject: [PATCH 16/57] The API returns "scopes":["#*"] for zones with no regional scope. The code only checked for '*' as the wildcard, so '#*' fell through to the scope-setting path. --- lib/providers/app_state_provider.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 6205faf..9151a42 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1086,11 +1086,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } // Set flood scope from API response (regional TX filtering) - // "*" = wildcard/global → no scope (unscoped flood, same as before) + // "*" or "#*" = wildcard/global → no scope (unscoped flood, same as before) // Any other value (e.g., "ottawa") → derive TransportKey and set scope final apiScopes = _apiService.scopes; - if (apiScopes.isNotEmpty && apiScopes.first != '*') { - final scopeName = apiScopes.first; + final firstScope = apiScopes.isNotEmpty ? apiScopes.first : null; + final isWildcard = firstScope == null || firstScope == '*' || firstScope == '#*'; + if (!isWildcard) { + final scopeName = firstScope; _scope = scopeName.startsWith('#') ? scopeName : '#$scopeName'; final scopeKey = CryptoService.deriveScopeKey(scopeName); debugLog('[CONN] Setting flood scope: $scopeName'); From d7ccdb0960be0ce117f1fe9a210cd3b743b5fee2 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Thu, 26 Feb 2026 22:07:28 -0500 Subject: [PATCH 17/57] Added dialog to upload logs window --- .build_version | 2 +- lib/screens/settings_screen.dart | 146 +---- lib/widgets/upload_logs_dialog.dart | 825 ++++++++++++++++++++++++++++ 3 files changed, 844 insertions(+), 129 deletions(-) create mode 100644 lib/widgets/upload_logs_dialog.dart diff --git a/.build_version b/.build_version index 9084fa2..524cb55 100644 --- a/.build_version +++ b/.build_version @@ -1 +1 @@ -1.1.0 +1.1.1 diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 9e5cea4..c068457 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -20,12 +20,12 @@ import '../utils/debug_logger_io.dart'; import '../utils/distance_formatter.dart'; import '../models/user_preferences.dart'; import '../services/debug_file_logger.dart'; -import '../services/debug_submit_service.dart'; import '../services/gps_simulator_service.dart'; import '../services/offline_session_service.dart'; import '../services/permission_disclosure_service.dart'; import '../utils/constants.dart'; import '../widgets/bug_report_dialog.dart'; +import '../widgets/upload_logs_dialog.dart'; import 'package:intl/intl.dart'; import '../widgets/app_toast.dart'; @@ -42,93 +42,19 @@ class _SettingsScreenState extends State { int _versionTapCount = 0; DateTime? _lastVersionTap; - // Debug log upload tracking - String? _uploadingFilePath; - final Set _uploadedFiles = {}; + Future _showUploadLogsDialog(BuildContext context, AppStateProvider appState) async { + final result = await showUploadLogsDialog(context, appState); - Future _uploadSingleLogFile(AppStateProvider appState, File file) async { - final filename = file.path.split('/').last; - - setState(() { - _uploadingFilePath = file.path; - }); - - try { - final service = DebugSubmitService(); - - // Use persistent device info - final publicKey = appState.devicePublicKey ?? - appState.lastConnectedPublicKey ?? - 'not-connected'; - final deviceName = appState.lastConnectedDeviceName ?? 'not-connected'; - - final success = await service.uploadDebugFileOnly( - file: file, - deviceId: deviceName, - publicKey: publicKey, - appVersion: AppConstants.appVersion, - devicePlatform: DebugSubmitService.getDevicePlatform(), - userNotes: 'Direct debug log upload from $deviceName', - ); - - service.dispose(); - - if (!mounted) return; - - if (success) { - setState(() { - _uploadedFiles.add(file.path); - _uploadingFilePath = null; - }); - AppToast.success(context, 'Uploaded $filename'); - } else { - setState(() { - _uploadingFilePath = null; - }); - AppToast.error(context, 'Failed to upload $filename'); - } - } catch (e) { - debugError('[SETTINGS] Log file upload error: $e'); - if (mounted) { - setState(() { - _uploadingFilePath = null; - }); - AppToast.error(context, 'Upload error: $e'); - } - } - } - - /// Upload the current (active) log file by rotating it first - Future _uploadCurrentLogFile(AppStateProvider appState, File currentFile) async { - final originalPath = currentFile.path; - - setState(() { - _uploadingFilePath = originalPath; - }); - - try { - // Rotate the log: closes current file, starts a new one - // The original file is now closed and safe to upload - await appState.prepareDebugLogsForUpload(); - - if (!mounted) return; - - // The original file still exists at the same path, now closed - final closedFile = File(originalPath); - if (!closedFile.existsSync()) { - throw Exception('Log file not found after rotation'); - } + if (!context.mounted || result == null) return; - // Now upload the closed file - await _uploadSingleLogFile(appState, closedFile); - } catch (e) { - debugError('[SETTINGS] Current log upload error: $e'); - if (mounted) { - setState(() { - _uploadingFilePath = null; - }); - AppToast.error(context, 'Upload error: $e'); + if (result.success) { + String message = 'Uploaded ${result.uploadedCount} log file${result.uploadedCount == 1 ? '' : 's'}'; + if (result.failedCount > 0) { + message += ' (${result.failedCount} failed)'; } + AppToast.success(context, message); + } else if (result.errorMessage != null) { + AppToast.error(context, result.errorMessage!); } } @@ -716,12 +642,18 @@ class _SettingsScreenState extends State { ), ), const Spacer(), - if (appState.debugLogFiles.isNotEmpty) + if (appState.debugLogFiles.isNotEmpty) ...[ + TextButton.icon( + icon: const Icon(Icons.cloud_upload, size: 18), + label: const Text('Upload'), + onPressed: () => _showUploadLogsDialog(context, appState), + ), TextButton.icon( icon: const Icon(Icons.delete_sweep, size: 18), label: const Text('Delete All'), onPressed: () => _confirmDeleteAllLogs(context, appState), ), + ], ], ), ), @@ -741,18 +673,13 @@ class _SettingsScreenState extends State { final file = entry.value; final filename = file.path.split('/').last; final sizeBytes = file.lengthSync(); - final isUploading = _uploadingFilePath == file.path; - final wasUploaded = _uploadedFiles.contains(file.path); - // First file (index 0) is the most recent/active log - can't upload final isCurrentLog = index == 0; - // Parse unix timestamp from filename (meshmapper-debug-{timestamp}.txt) final timestampMatch = RegExp(r'meshmapper-debug-(\d+)\.txt').firstMatch(filename); final fileDate = timestampMatch != null ? DateTime.fromMillisecondsSinceEpoch(int.parse(timestampMatch.group(1)!) * 1000) : null; final dateStr = fileDate != null ? DateFormat('MMM d, h:mm a').format(fileDate) : filename; - // Format size and show part count for oversized files String sizeDisplay; final partCount = DebugFileLogger.estimatePartCount(sizeBytes); if (sizeBytes >= DebugFileLogger.maxUploadSizeBytes) { @@ -775,48 +702,11 @@ class _SettingsScreenState extends State { trailing: Row( mainAxisSize: MainAxisSize.min, children: [ - // Upload button - if (wasUploaded) - Container( - width: 40, - height: 40, - alignment: Alignment.center, - child: const Icon( - Icons.check_circle, - size: 20, - color: Colors.green, - ), - ) - else if (isUploading) - Container( - width: 40, - height: 40, - alignment: Alignment.center, - child: const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ), - ) - else - IconButton( - icon: const Icon(Icons.cloud_upload, size: 20), - onPressed: _uploadingFilePath != null - ? null - : () => isCurrentLog - ? _uploadCurrentLogFile(appState, file) - : _uploadSingleLogFile(appState, file), - tooltip: isCurrentLog - ? 'Close log and upload' - : 'Upload to developer', - ), - // View button IconButton( icon: const Icon(Icons.visibility, size: 20), onPressed: () => _showLogViewer(context, appState, file), tooltip: 'View', ), - // Share button IconButton( icon: const Icon(Icons.share, size: 20), onPressed: () => appState.shareDebugLog(file), diff --git a/lib/widgets/upload_logs_dialog.dart b/lib/widgets/upload_logs_dialog.dart new file mode 100644 index 0000000..f97ddae --- /dev/null +++ b/lib/widgets/upload_logs_dialog.dart @@ -0,0 +1,825 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +import '../providers/app_state_provider.dart'; +import '../services/debug_file_logger.dart'; +import '../services/debug_submit_service.dart'; +import '../utils/constants.dart'; +import '../utils/debug_logger_io.dart'; + +/// Result of a log upload operation +class UploadLogsResult { + final bool success; + final int uploadedCount; + final int failedCount; + final String? errorMessage; + + const UploadLogsResult({ + required this.success, + this.uploadedCount = 0, + this.failedCount = 0, + this.errorMessage, + }); +} + +/// Bottom sheet for uploading debug logs with a mandatory description +class UploadLogsSheet extends StatefulWidget { + final AppStateProvider appState; + final ScrollController scrollController; + + const UploadLogsSheet({ + super.key, + required this.appState, + required this.scrollController, + }); + + @override + State createState() => _UploadLogsSheetState(); +} + +class _UploadLogsSheetState extends State { + final _formKey = GlobalKey(); + final _descriptionController = TextEditingController(); + + final Set _selectedLogFiles = {}; + bool _isSubmitting = false; + String? _errorMessage; + + // Progress tracking + double _progress = 0.0; + String _progressStatus = ''; + int? _currentFile; + int? _totalFiles; + + // Uploadable log files + List _availableLogFiles = []; + bool _isLoadingFiles = true; + + @override + void initState() { + super.initState(); + _loadUploadableFiles(); + } + + Future _loadUploadableFiles() async { + try { + final files = await DebugFileLogger.listUploadableLogFiles(); + if (mounted) { + setState(() { + _availableLogFiles = files; + _isLoadingFiles = false; + // Select all by default + _selectedLogFiles.addAll(files.map((f) => f.path)); + }); + } + } catch (e) { + debugError('[DEBUG] Failed to load uploadable files: $e'); + if (mounted) { + setState(() { + _availableLogFiles = []; + _isLoadingFiles = false; + }); + } + } + } + + @override + void dispose() { + _descriptionController.dispose(); + super.dispose(); + } + + void _toggleFile(String path) { + setState(() { + if (_selectedLogFiles.contains(path)) { + _selectedLogFiles.remove(path); + } else { + _selectedLogFiles.add(path); + } + }); + } + + void _onProgressUpdate(BugReportProgress progress) { + if (mounted) { + setState(() { + _progress = progress.progress; + _progressStatus = progress.status; + _currentFile = progress.currentFile; + _totalFiles = progress.totalFiles; + }); + } + } + + Future _submit() async { + if (!_formKey.currentState!.validate()) return; + + if (_selectedLogFiles.isEmpty) { + setState(() { + _errorMessage = 'Please select at least one log file to upload'; + }); + return; + } + + // Warn user about GPS data in debug logs + final confirmed = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Location Data Warning'), + content: const Text( + 'Debug logs may contain your approximate GPS coordinates ' + 'from your wardriving session. This location history will ' + 'be included in the uploaded files.\n\n' + 'Do you want to continue?', + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text('Continue'), + ), + ], + ), + ); + if (confirmed != true) return; + + setState(() { + _isSubmitting = true; + _errorMessage = null; + _progress = 0.0; + _progressStatus = 'Preparing logs...'; + _currentFile = null; + _totalFiles = null; + }); + + try { + // Rotate the current log file now that the user has committed to uploading + final freshFiles = await widget.appState.prepareDebugLogsForUpload(); + + // Build the upload list using the user's selection applied to the freshly rotated files. + // Selected paths from before rotation still match, plus any newly rotated file is included. + final selectedPaths = Set.from(_selectedLogFiles); + final filesToUpload = freshFiles + .where((f) => selectedPaths.contains(f.path)) + .toList(); + + // If the rotation produced a new file that wasn't in the original selection + // (i.e. the previously-active log that just got rotated), include it too + // since the user selected "all" initially and this file has new content. + final newFiles = freshFiles.where((f) => !selectedPaths.contains(f.path)).toList(); + if (newFiles.isNotEmpty && selectedPaths.length == _availableLogFiles.length) { + filesToUpload.addAll(newFiles); + } + + if (filesToUpload.isEmpty) { + if (mounted) { + setState(() { + _errorMessage = 'No log files to upload after preparation'; + _isSubmitting = false; + _progress = 0.0; + _progressStatus = ''; + }); + } + return; + } + + final service = DebugSubmitService(); + + final publicKey = widget.appState.devicePublicKey ?? + widget.appState.lastConnectedPublicKey ?? + 'not-connected'; + final deviceName = widget.appState.lastConnectedDeviceName ?? 'not-connected'; + final userNotes = _descriptionController.text.trim(); + + int uploadedCount = 0; + int failedCount = 0; + final totalFiles = filesToUpload.length; + + for (int i = 0; i < totalFiles; i++) { + final file = filesToUpload[i]; + final progressBase = i / totalFiles; + final progressPerFile = 1.0 / totalFiles; + + _onProgressUpdate(BugReportProgress( + status: 'Uploading file ${i + 1} of $totalFiles...', + progress: progressBase, + currentFile: i + 1, + totalFiles: totalFiles, + )); + + final success = await service.uploadDebugFileOnly( + file: file, + deviceId: deviceName, + publicKey: publicKey, + appVersion: AppConstants.appVersion, + devicePlatform: DebugSubmitService.getDevicePlatform(), + userNotes: userNotes, + onProgress: (p) { + _onProgressUpdate(BugReportProgress( + status: p.status, + progress: (progressBase + p.progress * progressPerFile).clamp(0.0, 1.0), + currentFile: i + 1, + totalFiles: totalFiles, + )); + }, + ); + + if (success) { + uploadedCount++; + } else { + failedCount++; + } + } + + service.dispose(); + + if (!mounted) return; + + final result = UploadLogsResult( + success: uploadedCount > 0, + uploadedCount: uploadedCount, + failedCount: failedCount, + errorMessage: failedCount > 0 ? '$failedCount file(s) failed to upload' : null, + ); + + Navigator.of(context).pop(result); + } catch (e) { + debugError('[DEBUG] Upload logs error: $e'); + if (mounted) { + setState(() { + _errorMessage = 'Error: $e'; + _isSubmitting = false; + _progress = 0.0; + _progressStatus = ''; + }); + } + } + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + if (_isSubmitting) { + return _buildProgressView(theme); + } + + return Column( + children: [ + // Drag handle + Center( + child: Container( + width: 40, + height: 4, + margin: const EdgeInsets.only(top: 12, bottom: 8), + decoration: BoxDecoration( + color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.4), + borderRadius: BorderRadius.circular(2), + ), + ), + ), + + // Header + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + child: Row( + children: [ + Icon(Icons.cloud_upload_outlined, color: theme.colorScheme.primary, size: 28), + const SizedBox(width: 12), + Text('Upload Logs', style: theme.textTheme.titleLarge), + const Spacer(), + IconButton( + icon: const Icon(Icons.close), + onPressed: _isSubmitting ? null : () => Navigator.of(context).pop(), + tooltip: 'Close', + ), + ], + ), + ), + + const Divider(height: 1), + + // Scrollable content + Expanded( + child: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + behavior: HitTestBehavior.opaque, + child: Form( + key: _formKey, + child: ListView( + controller: widget.scrollController, + padding: const EdgeInsets.all(20), + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + children: [ + // Explanation text + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.primary.withValues(alpha: 0.3), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + Icons.info_outline, + size: 20, + color: theme.colorScheme.primary, + ), + const SizedBox(width: 10), + Expanded( + child: Text( + 'Upload your debug logs directly to the MeshMapper developers. ' + 'This helps us diagnose issues and improve the app.', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 24), + + // Description field (mandatory) + _buildSectionLabel(theme, Icons.description, 'Description'), + const SizedBox(height: 8), + TextFormField( + controller: _descriptionController, + textCapitalization: TextCapitalization.sentences, + decoration: _buildInputDecoration( + theme, + hintText: 'Briefly describe why you\'re uploading these logs...', + alignLabelWithHint: true, + ), + maxLines: 3, + maxLength: 500, + enabled: !_isSubmitting, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'A description is required'; + } + if (value.trim().length < 10) { + return 'Please provide more detail (at least 10 characters)'; + } + return null; + }, + ), + const SizedBox(height: 16), + + // Log files section + _buildSectionLabel(theme, Icons.folder_open, 'Log Files'), + const SizedBox(height: 8), + + if (_isLoadingFiles) + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.3), + ), + ), + child: Row( + children: [ + SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 12), + Text( + 'Preparing log files...', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ) + else if (_availableLogFiles.isEmpty) + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.3), + ), + ), + child: Row( + children: [ + Icon( + Icons.info_outline, + size: 20, + color: theme.colorScheme.onSurfaceVariant, + ), + const SizedBox(width: 12), + Text( + 'No log files available to upload', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ) + else + Container( + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.3), + ), + ), + child: Column( + children: [ + // Select all / deselect all header + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Text( + '${_selectedLogFiles.length} of ${_availableLogFiles.length} selected', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const Spacer(), + TextButton( + onPressed: () { + setState(() { + if (_selectedLogFiles.length == _availableLogFiles.length) { + _selectedLogFiles.clear(); + } else { + _selectedLogFiles.clear(); + _selectedLogFiles.addAll( + _availableLogFiles.map((f) => f.path), + ); + } + }); + }, + child: Text( + _selectedLogFiles.length == _availableLogFiles.length + ? 'Deselect All' + : 'Select All', + ), + ), + ], + ), + ), + Divider( + height: 1, + color: theme.colorScheme.outline.withValues(alpha: 0.3), + ), + // File list + ...List.generate(_availableLogFiles.length, (index) { + final file = _availableLogFiles[index]; + final filename = file.path.split('/').last; + final sizeBytes = file.lengthSync(); + final isSelected = _selectedLogFiles.contains(file.path); + + String sizeDisplay; + final partCount = DebugFileLogger.estimatePartCount(sizeBytes); + if (sizeBytes >= DebugFileLogger.maxUploadSizeBytes) { + final sizeMb = (sizeBytes / 1024 / 1024).toStringAsFixed(1); + sizeDisplay = '$sizeMb MB ($partCount parts)'; + } else { + sizeDisplay = '${(sizeBytes / 1024).toStringAsFixed(1)} KB'; + } + + return ListTile( + dense: true, + leading: Checkbox( + value: isSelected, + onChanged: _isSubmitting + ? null + : (_) => _toggleFile(file.path), + ), + title: Text( + filename, + style: const TextStyle(fontSize: 13), + ), + trailing: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + sizeDisplay, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + onTap: _isSubmitting ? null : () => _toggleFile(file.path), + ); + }), + ], + ), + ), + + // Error message + if (_errorMessage != null) ...[ + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: theme.colorScheme.error.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: theme.colorScheme.error.withValues(alpha: 0.3), + ), + ), + child: Row( + children: [ + Icon( + Icons.error_outline, + size: 20, + color: theme.colorScheme.error, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage!, + style: TextStyle(color: theme.colorScheme.error), + ), + ), + ], + ), + ), + ], + + SizedBox(height: MediaQuery.of(context).padding.bottom + 80), + ], + ), + ), + ), + ), + + // Sticky bottom action bar + Container( + padding: EdgeInsets.fromLTRB( + 20, + 12, + 20, + MediaQuery.of(context).padding.bottom + 12, + ), + decoration: BoxDecoration( + color: theme.colorScheme.surface, + border: Border( + top: BorderSide( + color: theme.colorScheme.outline.withValues(alpha: 0.3), + ), + ), + ), + child: Row( + children: [ + Expanded( + child: OutlinedButton( + onPressed: _isSubmitting ? null : () => Navigator.of(context).pop(), + style: OutlinedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 12), + ), + child: const Text('Cancel'), + ), + ), + const SizedBox(width: 12), + Expanded( + flex: 2, + child: FilledButton.icon( + onPressed: _isSubmitting || _availableLogFiles.isEmpty + ? null + : _submit, + icon: const Icon(Icons.cloud_upload, size: 18), + label: Text( + _selectedLogFiles.isEmpty + ? 'Upload' + : 'Upload ${_selectedLogFiles.length} Log${_selectedLogFiles.length == 1 ? '' : 's'}', + ), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 12), + ), + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildProgressView(ThemeData theme) { + return Column( + children: [ + // Drag handle + Center( + child: Container( + width: 40, + height: 4, + margin: const EdgeInsets.only(top: 12, bottom: 8), + decoration: BoxDecoration( + color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.4), + borderRadius: BorderRadius.circular(2), + ), + ), + ), + + // Header + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + child: Row( + children: [ + Icon(Icons.cloud_upload_outlined, color: theme.colorScheme.primary, size: 28), + const SizedBox(width: 12), + Text('Uploading...', style: theme.textTheme.titleLarge), + ], + ), + ), + + const Divider(height: 1), + + // Progress content + Expanded( + child: Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer.withValues(alpha: 0.3), + shape: BoxShape.circle, + ), + child: Center( + child: SizedBox( + width: 40, + height: 40, + child: CircularProgressIndicator( + strokeWidth: 3, + color: theme.colorScheme.primary, + ), + ), + ), + ), + const SizedBox(height: 32), + + Text( + _progressStatus.isNotEmpty ? _progressStatus : 'Please wait...', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + + if (_totalFiles != null && _currentFile != null) + Text( + 'File $_currentFile of $_totalFiles', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: 24), + + SizedBox( + width: 250, + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(6), + child: LinearProgressIndicator( + value: _progress, + backgroundColor: theme.colorScheme.surfaceContainerHighest, + color: theme.colorScheme.primary, + minHeight: 8, + ), + ), + const SizedBox(height: 8), + Text( + '${(_progress * 100).toInt()}%', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + + Padding( + padding: EdgeInsets.fromLTRB( + 20, + 12, + 20, + MediaQuery.of(context).padding.bottom + 12, + ), + child: Text( + 'Please don\'t close this screen', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + ], + ); + } + + Widget _buildSectionLabel(ThemeData theme, IconData icon, String label) { + return Row( + children: [ + Icon(icon, size: 18, color: theme.colorScheme.primary), + const SizedBox(width: 8), + Text( + label, + style: theme.textTheme.titleSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.w600, + ), + ), + ], + ); + } + + InputDecoration _buildInputDecoration( + ThemeData theme, { + String? hintText, + bool alignLabelWithHint = false, + }) { + return InputDecoration( + hintText: hintText, + alignLabelWithHint: alignLabelWithHint, + filled: true, + fillColor: theme.colorScheme.surfaceContainerHighest, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: theme.colorScheme.outline), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: theme.colorScheme.outline.withValues(alpha: 0.5), + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: theme.colorScheme.primary, width: 2), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: theme.colorScheme.error), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: theme.colorScheme.error, width: 2), + ), + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + ); + } +} + +/// Show the upload logs dialog and return the result +Future showUploadLogsDialog( + BuildContext context, + AppStateProvider appState, +) async { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + backgroundColor: Theme.of(context).colorScheme.surface, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => DraggableScrollableSheet( + initialChildSize: 0.85, + minChildSize: 0.5, + maxChildSize: 0.95, + expand: false, + builder: (context, scrollController) => UploadLogsSheet( + appState: appState, + scrollController: scrollController, + ), + ), + ); +} From 18e2c46deefb3e5de63ad7839b058647371d3ea2 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 7 Mar 2026 08:16:13 -0500 Subject: [PATCH 18/57] =?UTF-8?q?=20=20Add=20Discovery=20Drop=20feature=20?= =?UTF-8?q?=E2=80=94=20failed=20discovery=20requests=20can=20now=20be=20re?= =?UTF-8?q?ported=20to=20the=20API=20as=20failed=20pings=20(repeater=5Fid:?= =?UTF-8?q?=20"None"),=20helping=20identify=20dead=20zones.=20Includes=20?= =?UTF-8?q?=20=20user=20toggle=20in=20Settings=20(default=20off),=20API-en?= =?UTF-8?q?forced=20override=20via=20disc=5Fdrop=20auth=20field,=20red=20m?= =?UTF-8?q?arkers=20on=20map/noise=20floor=20chart=20for=20failed=20discov?= =?UTF-8?q?eries=20when=20enabled.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + lib/models/api_queue_item.dart | 33 ++++++++++++++ lib/models/user_preferences.dart | 12 ++++- lib/providers/app_state_provider.dart | 22 ++++++++- lib/screens/settings_screen.dart | 65 +++++++++++++++++++++++++++ lib/services/api_queue_service.dart | 34 ++++++++++++++ lib/services/api_service.dart | 11 +++++ lib/services/ping_service.dart | 15 +++++++ lib/widgets/map_widget.dart | 8 ++-- 9 files changed, 196 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 068e8e0..d7c37fe 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ ios/Flutter/flutter_export_environment.sh *.g.dart # Debug logs +debug/ debuglog/ meshmapper-debug-*.txt diff --git a/lib/models/api_queue_item.dart b/lib/models/api_queue_item.dart index 67714bb..57145e9 100644 --- a/lib/models/api_queue_item.dart +++ b/lib/models/api_queue_item.dart @@ -138,10 +138,43 @@ class ApiQueueItem extends HiveObject { ); } + /// Create from a failed DISC discovery (no nodes responded) + factory ApiQueueItem.fromDiscDrop({ + required double latitude, + required double longitude, + required int timestamp, + required bool externalAntenna, + int? noiseFloor, + }) { + return ApiQueueItem( + type: 'DISC', + latitude: latitude, + longitude: longitude, + timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000), + heardRepeats: 'None', + canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate + externalAntenna: externalAntenna, + noiseFloor: noiseFloor, + ); + } + /// Convert to API JSON format (matches WebClient exactly) Map toApiJson() { // For DISC type, parse the heardRepeats field to extract individual values if (type == 'DISC') { + // Failed discovery (no nodes responded) + if (heardRepeats == 'None') { + return { + 'type': type, + 'lat': latitude, + 'lon': longitude, + 'noisefloor': noiseFloor, + 'repeater_id': 'None', + 'timestamp': timestamp.millisecondsSinceEpoch ~/ 1000, + 'external_antenna': externalAntenna, + }; + } + // Format: "repeaterId:nodeType:localSnr:localRssi:remoteSnr:pubkeyFull" final parts = heardRepeats.split(':'); return { diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index a24e904..a653799 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -70,6 +70,9 @@ class UserPreferences { /// Anonymous mode: rename companion to "Anonymous" during wardriving final bool anonymousMode; + /// Discovery drop: count failed discoveries as failed pings and report to API + final bool discDropEnabled; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -94,6 +97,7 @@ class UserPreferences { this.mapRotationLocked = false, this.disableRssiFilter = false, this.anonymousMode = false, + this.discDropEnabled = false, }); /// Create from JSON (for persistence) @@ -122,6 +126,7 @@ class UserPreferences { mapRotationLocked: (json['mapRotationLocked'] as bool?) ?? false, disableRssiFilter: (json['disableRssiFilter'] as bool?) ?? false, anonymousMode: (json['anonymousMode'] as bool?) ?? false, + discDropEnabled: (json['discDropEnabled'] as bool?) ?? false, ); } @@ -151,6 +156,7 @@ class UserPreferences { 'mapRotationLocked': mapRotationLocked, 'disableRssiFilter': disableRssiFilter, 'anonymousMode': anonymousMode, + 'discDropEnabled': discDropEnabled, }; } @@ -179,6 +185,7 @@ class UserPreferences { bool? mapRotationLocked, bool? disableRssiFilter, bool? anonymousMode, + bool? discDropEnabled, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -204,6 +211,7 @@ class UserPreferences { mapRotationLocked: mapRotationLocked ?? this.mapRotationLocked, disableRssiFilter: disableRssiFilter ?? this.disableRssiFilter, anonymousMode: anonymousMode ?? this.anonymousMode, + discDropEnabled: discDropEnabled ?? this.discDropEnabled, ); } @@ -254,7 +262,8 @@ class UserPreferences { other.mapAlwaysNorth == mapAlwaysNorth && other.mapRotationLocked == mapRotationLocked && other.disableRssiFilter == disableRssiFilter && - other.anonymousMode == anonymousMode; + other.anonymousMode == anonymousMode && + other.discDropEnabled == discDropEnabled; } @override @@ -282,6 +291,7 @@ class UserPreferences { mapRotationLocked, disableRssiFilter, anonymousMode, + discDropEnabled, ]); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 9151a42..a3a019c 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -391,6 +391,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get hasApiSession => _apiService.hasSession; bool get isApiRxOnlyMode => hasApiSession && !txAllowed && rxAllowed; bool get enforceHybrid => _apiService.enforceHybrid; + bool get enforceDiscDrop => _apiService.enforceDiscDrop; + bool get discDropEnabled => _preferences.discDropEnabled || _apiService.enforceDiscDrop; int get minModeInterval => _apiService.minModeInterval; // Offline mode @@ -1109,6 +1111,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[CONN] Hybrid mode force-enabled by regional admin'); } + // Enforce discovery drop if required by regional admin + if (_apiService.enforceDiscDrop && !_preferences.discDropEnabled) { + _preferences = _preferences.copyWith(discDropEnabled: true); + debugLog('[CONN] Discovery drop force-enabled by regional admin'); + } + // Enforce minimum auto-ping interval if required by regional admin if (_preferences.autoPingInterval < _apiService.minModeInterval) { _preferences = _preferences.copyWith(autoPingInterval: _apiService.minModeInterval); @@ -1162,6 +1170,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Check if TX is allowed by API (zone capacity) _pingService!.checkTxAllowed = () => txAllowed; + // Check if discovery drop is enabled + _pingService!.getDiscDropEnabled = () => discDropEnabled; + _pingService!.onTxPing = (ping) { _txPings.add(ping); if (_txPings.length > _maxMapPins) _txPings.removeAt(0); @@ -1348,8 +1359,17 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + PingEventType eventType; + if (success) { + eventType = PingEventType.discSuccess; + } else if (discDropEnabled) { + eventType = PingEventType.txFail; + } else { + eventType = PingEventType.discFail; + } + recordPingEvent( - success ? PingEventType.discSuccess : PingEventType.discFail, + eventType, latitude: lat, longitude: lon, repeaters: repeaters, diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index c068457..dca29a8 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -180,6 +180,35 @@ class _SettingsScreenState extends State { }, ), + // Discovery Drop Toggle + SwitchListTile( + secondary: const Icon(Icons.signal_wifi_off), + title: Row( + children: [ + const Text('Discovery Drop'), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showDiscDropInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + subtitle: appState.enforceDiscDrop + ? const Text( + 'Enabled by Regional Admin', + style: TextStyle(color: Colors.amber), + ) + : const Text('Count failed discoveries as failed pings'), + value: appState.enforceDiscDrop ? true : prefs.discDropEnabled, + onChanged: (isAutoMode || appState.enforceDiscDrop) ? null : (value) { + appState.updatePreferences(prefs.copyWith(discDropEnabled: value)); + }, + ), + // CARpeater Filter Setting SwitchListTile( secondary: const Icon(Icons.filter_alt), @@ -975,6 +1004,42 @@ class _SettingsScreenState extends State { ); } + void _showDiscDropInfo(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.signal_wifi_off, size: 24), + SizedBox(width: 8), + Text('Discovery Drop'), + ], + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'When enabled, failed discovery requests (no repeater responded) are reported to the API as failed pings, helping identify dead zones in the mesh network.', + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 12), + Text( + 'Discovery requests require Repeater firmware 1.10+. If the majority of the mesh is not on this version, it may produce false "no coverage" areas/failed pings.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Got it'), + ), + ], + ), + ); + } + void _showIntervalSelector(BuildContext context, AppStateProvider appState) { final minInterval = appState.minModeInterval; var currentInterval = appState.preferences.autoPingInterval; diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index b2f708b..89b040f 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -333,6 +333,40 @@ class ApiQueueService { }); } + /// Enqueue a failed DISC discovery (no nodes responded) + Future enqueueDiscDrop({ + required double latitude, + required double longitude, + required int timestamp, + required bool externalAntenna, + int? noiseFloor, + }) async { + final item = ApiQueueItem.fromDiscDrop( + latitude: latitude, + longitude: longitude, + timestamp: timestamp, + externalAntenna: externalAntenna, + noiseFloor: noiseFloor, + ); + + // In offline mode, accumulate to offline pings list instead of queue + if (offlineMode) { + _offlinePings.add(item.toApiJson()); + debugLog('[API QUEUE] DISC drop enqueued (offline)'); + return; + } + + await _safeWrite((box) => box.add(item)); + debugLog('[API QUEUE] DISC drop enqueued at $latitude, $longitude (queue size: $queueSize)'); + onQueueUpdated?.call(queueSize); + _pingFlushTimer?.cancel(); + _pingFlushTimer = Timer(const Duration(seconds: 5), () { + debugLog('[API QUEUE] Ping flush timer fired'); + _flushRxBuffer(); + _uploadBatch(); + }); + } + // Guard to prevent concurrent RX buffer flushes bool _isFlushing = false; diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 6b5b6be..34bb60d 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -42,6 +42,7 @@ class ApiService { List _channels = []; List _scopes = []; bool _enforceHybrid = false; + bool _enforceDiscDrop = false; int _minModeInterval = 15; /// Callback to get current GPS coordinates for heartbeat @@ -57,6 +58,9 @@ class ApiService { /// Whether hybrid mode is enforced by regional admin bool get enforceHybrid => _enforceHybrid; + /// Whether discovery drop is enforced by regional admin + bool get enforceDiscDrop => _enforceDiscDrop; + /// Minimum auto-ping interval enforced by regional admin (seconds) int get minModeInterval => _minModeInterval; @@ -329,6 +333,12 @@ class ApiService { debugLog('[API] Regional admin enforces hybrid mode'); } + // Parse disc_drop flag from auth response + _enforceDiscDrop = data['disc_drop'] == true; + if (_enforceDiscDrop) { + debugLog('[API] Regional admin enforces discovery drop'); + } + // Parse min_mode_interval from auth response final minInterval = data['min_mode_interval']; if (minInterval is int && minInterval > 0) { @@ -638,6 +648,7 @@ class ApiService { _channels = []; _scopes = []; _enforceHybrid = false; + _enforceDiscDrop = false; _minModeInterval = 15; _heartbeatTimer?.cancel(); _heartbeatTimer = null; diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 1b920a2..54513f4 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -108,6 +108,9 @@ class PingService { /// Callback to get the external antenna value for API payloads bool Function()? getExternalAntenna; + /// Callback to check if discovery drop is enabled (failed discoveries → API) + bool Function()? getDiscDropEnabled; + /// Callback to check if TX is allowed by API (zone capacity check) bool Function()? checkTxAllowed; @@ -1129,6 +1132,18 @@ class PingService { onStatsUpdated?.call(_stats); } else { debugLog('[DISC] No nodes discovered'); + + // Queue failed discovery to API if disc drop is enabled + if (getDiscDropEnabled?.call() == true) { + _apiQueue.enqueueDiscDrop( + latitude: position.latitude, + longitude: position.longitude, + timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000, + externalAntenna: getExternalAntenna?.call() ?? false, + noiseFloor: _pendingTxNoiseFloor, + ); + debugLog('[DISC] Discovery drop queued (no response)'); + } } // Entry already added to log via onDiscPing - no need to fire onDiscoveryComplete diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 0940ae0..c478080 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -683,7 +683,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // DISC markers (purple circles for discovery observations) MarkerLayer( - markers: _buildDiscMarkers(appState.discLogEntries), + markers: _buildDiscMarkers(appState.discLogEntries, appState.discDropEnabled), ), // Repeater markers (magenta circles with ID) @@ -1566,7 +1566,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { }).toList(); } - List _buildDiscMarkers(List entries) { + List _buildDiscMarkers(List entries, bool discDropEnabled) { return entries.map((entry) { return Marker( point: LatLng(entry.latitude, entry.longitude), @@ -1576,7 +1576,9 @@ class _MapWidgetState extends State with TickerProviderStateMixin { onTap: () => _showDiscPingDetails(entry), child: Container( decoration: BoxDecoration( - color: entry.nodeCount == 0 ? Colors.grey : _discMarkerColor, + color: entry.nodeCount == 0 + ? (discDropEnabled ? Colors.red : Colors.grey) + : _discMarkerColor, shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), boxShadow: const [ From c5d0947d98d3f4dbefd84f1a8fd8a21a113d7bf0 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 7 Mar 2026 22:35:48 -0500 Subject: [PATCH 19/57] New Feature MeshCore firmware v1.14.0+ supports multi-byte path hashes (1, 2, or 3 bytes per hop), expanding repeater ID space from 256 to 65K or 16M unique IDs. The app now fully supports this protocol change. --- DEVELOPMENT.md | 13 +- lib/providers/app_state_provider.dart | 143 +++++++++++++++++- lib/screens/connection_screen.dart | 87 +++++++++++ lib/screens/settings_screen.dart | 112 +++++++++++++- lib/services/api_service.dart | 19 +++ lib/services/meshcore/connection.dart | 44 +++++- lib/services/meshcore/packet_metadata.dart | 123 +++++++++------ lib/services/meshcore/packet_validator.dart | 2 +- lib/services/meshcore/protocol_constants.dart | 1 + lib/services/meshcore/rx_logger.dart | 18 +-- lib/services/meshcore/tx_tracker.dart | 14 +- lib/services/meshcore/unified_rx_handler.dart | 2 +- lib/widgets/repeater_id_chip.dart | 13 +- 13 files changed, 502 insertions(+), 89 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index ac71218..b7b1ad2 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -295,10 +295,21 @@ Keeps the screen on during auto-ping to prevent device sleep during wardriving s ### Packet Structure - Custom binary protocol with header byte (0x11 = GROUP_TEXT, 0x21 = ADVERT) -- Path encoding: hop count + repeater IDs (4 bytes each) +- Path encoding: `pathLen` byte encodes hash size (top 2 bits) + hop count (bottom 6 bits), followed by `hopCount * hashSize` path bytes + - `pathHashSize = (pathLen >> 6) + 1` → 1, 2, 3, or 4 bytes per hop + - `pathHashCount = pathLen & 63` → 0-63 hops - SNR/RSSI metadata in BLE event payload - Encrypted message payload (AES-ECB with channel key) +### Multi-Byte Path Support (v1.14.0+) +- **Purpose**: Expands repeater ID space from 256 (1-byte) to 65K (2-byte) or 16M (3-byte) unique IDs +- **TX mode**: Configured via `CMD_SET_PATH_HASH_MODE = 61 (0x3D)` — `[0x3D][0x00][mode]` where mode=0→1-byte, 1→2-byte, 2→3-byte +- **RX auto-detect**: Each received packet's `pathLen` byte is decoded to determine hash size, regardless of the user's TX setting +- **DeviceInfo**: v10+ firmware includes `path_hash_mode` byte after manufacturer + firmware version fields +- **API enforcement**: Auth response may include `hop_bytes` (1/2/3) to enforce regional path byte size +- **Lifecycle**: Radio mode is set during connection and restored to original on clean disconnect. Unclean disconnect leaves radio in configured mode. +- **Discovery pings**: NOT affected — multi-byte paths apply only to TX/RX channel messages + ## Platform-Specific Notes ### Web (Chrome/Edge only) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index a3a019c..968a646 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -244,6 +244,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Regional scope from API (for UI display and flood filtering) String? _scope; + // Path hash mode tracking (for multi-byte path support) + int? _originalPathHashMode; // Device's mode BEFORE we changed it (from DeviceInfo) + bool _userChangedPathMode = false; // True if user manually changed hopBytes while connected + int _hopBytes = 1; // Runtime-only: current hop byte size (read from device, not persisted) + // Noise floor session tracking (for graph feature) NoiseFloorSession? _currentNoiseFloorSession; List _storedNoiseFloorSessions = []; @@ -394,6 +399,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get enforceDiscDrop => _apiService.enforceDiscDrop; bool get discDropEnabled => _preferences.discDropEnabled || _apiService.enforceDiscDrop; int get minModeInterval => _apiService.minModeInterval; + bool get enforceHopBytes => _apiService.enforceHopBytes; + int get hopBytes => _hopBytes; + int get effectiveHopBytes => enforceHopBytes ? _apiService.apiHopBytes : _hopBytes; + bool get supportsMultiBytePaths => _originalPathHashMode != null; // Offline mode bool get offlineMode => _preferences.offlineMode; @@ -1123,6 +1132,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[CONN] Auto-ping interval bumped to ${_apiService.minModeInterval}s by regional admin'); } + // Configure multi-byte path hash mode on radio + await _configurePathHashMode(); + // Create ping service with wakelock (create new instance per connection) _pingService = PingService( gpsService: _gpsService, @@ -1139,12 +1151,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { disableRssiFilter: _preferences.disableRssiFilter, shouldIgnoreRepeater: (String repeaterId) { // Same filter as RxLogger - check user preferences for ignored repeater ID + // Uses startsWith() for prefix matching across different hop byte sizes final prefs = _preferences; if (prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null) { - // Case-insensitive comparison (both uppercase) final ignored = prefs.ignoreRepeaterId!.toUpperCase(); final current = repeaterId.toUpperCase(); - return current == ignored; + return current.startsWith(ignored) || ignored.startsWith(current); } return false; }, @@ -1763,6 +1775,126 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { /// Full disconnect cleanup - called on normal BLE disconnect (user-requested or no remembered device) /// Extracted from the original BLE disconnect listener + /// Configure multi-byte path hash mode on the radio during connection + /// Reads device's current mode, determines effective mode, and sends command if needed + Future _configurePathHashMode() async { + final deviceInfo = _meshCoreConnection?.deviceInfo; + if (deviceInfo == null) return; + + // Store the device's current mode (from DeviceInfo response) + _originalPathHashMode = deviceInfo.pathHashMode; + + // Sync runtime hopBytes from device's current mode + if (_originalPathHashMode != null) { + final deviceHopBytes = _originalPathHashMode! + 1; + _hopBytes = deviceHopBytes; + debugLog('[PATH] Read device path mode: $deviceHopBytes-byte'); + } else { + _hopBytes = 1; + } + + final effective = effectiveHopBytes; + final deviceMode = _originalPathHashMode ?? 0; // null = old firmware, treat as 0 (1-byte) + final deviceHopBytes = deviceMode + 1; + + if (effective != deviceHopBytes && _originalPathHashMode != null) { + // Need to change the radio's path hash mode + try { + await _meshCoreConnection!.setPathHashMode(effective - 1); + debugLog('[PATH] Set path hash mode: device was $deviceHopBytes-byte, now $effective-byte'); + + // Show warning popup if changing from 1-byte to multi-byte + if (deviceMode == 0 && effective > 1) { + final reason = enforceHopBytes + ? 'set by your regional admin' + : 'set in your app preferences'; + _pendingPathHashWarning = (hopBytes: effective, reason: reason); + notifyListeners(); // Trigger UI to show warning + } + } catch (e) { + debugError('[PATH] Failed to set path hash mode: $e'); + } + } else if (_originalPathHashMode == null && effective > 1) { + // Old firmware doesn't support multi-byte paths — warn user, fall back to 1-byte + debugWarn('[PATH] Device firmware does not report path_hash_mode, cannot set $effective-byte paths'); + if (enforceHopBytes) { + _pendingPathHashWarning = (hopBytes: effective, reason: 'firmware_unsupported'); + notifyListeners(); + } + } else { + debugLog('[PATH] Path hash mode OK: device=$deviceHopBytes-byte, effective=$effective-byte'); + } + } + + /// Restore radio to original path hash mode on clean disconnect + /// Skipped if the user manually changed the setting — they know what they're doing + Future _restorePathHashMode() async { + if (_originalPathHashMode == null) return; + + if (_userChangedPathMode) { + debugLog('[PATH] User manually changed path mode, not restoring on disconnect'); + _originalPathHashMode = null; + _userChangedPathMode = false; + return; + } + + final effective = effectiveHopBytes; + final deviceMode = _originalPathHashMode!; + final deviceHopBytes = deviceMode + 1; + + if (effective != deviceHopBytes) { + try { + await _meshCoreConnection?.setPathHashMode(deviceMode); + debugLog('[PATH] Restored path hash mode to original: $deviceHopBytes-byte'); + } catch (e) { + debugError('[PATH] Failed to restore path hash mode: $e'); + } + } + _originalPathHashMode = null; + _userChangedPathMode = false; + } + + /// Send path hash mode to radio immediately when user changes setting while connected + void _applyLivePathHashMode(int newHopBytes) { + if (_originalPathHashMode == null) { + // Old firmware — can't send command, show warning + debugWarn('[PATH] Cannot change path mode: firmware does not support it'); + _pendingPathHashWarning = (hopBytes: newHopBytes, reason: 'firmware_unsupported'); + _hopBytes = 1; // Force back to 1 + notifyListeners(); + return; + } + + _hopBytes = newHopBytes; + _userChangedPathMode = true; + final mode = newHopBytes - 1; // Convert 1/2/3 → mode 0/1/2 + _meshCoreConnection?.setPathHashMode(mode); + debugLog('[PATH] User changed path mode to $newHopBytes-byte (sent to radio)'); + notifyListeners(); + } + + /// Set hop bytes (called from settings UI). Each companion device may differ. + void setHopBytes(int value) { + if (value < 1 || value > 3) return; + if (value == _hopBytes) return; + + if (isConnected) { + _applyLivePathHashMode(value); + } else { + _hopBytes = value; + notifyListeners(); + } + } + + /// Pending path hash warning data (for UI to show dialog) + ({int hopBytes, String reason})? _pendingPathHashWarning; + ({int hopBytes, String reason})? get pendingPathHashWarning => _pendingPathHashWarning; + + /// Clear the pending warning after UI has shown it + void clearPathHashWarning() { + _pendingPathHashWarning = null; + } + Future _fullDisconnectCleanup() async { _connectionStep = ConnectionStep.disconnected; @@ -2061,6 +2193,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _originalDeviceName = null; } + // Restore original path hash mode before disconnect (while BLE still connected) + await _restorePathHashMode(); + // Clear flood scope before disconnect (safety — BLE disconnect resets radio state anyway) try { await _meshCoreConnection?.clearFloodScope(); @@ -2105,6 +2240,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _currentNoiseFloor = null; _currentBatteryPercent = null; _authType = null; + _originalPathHashMode = null; + _userChangedPathMode = false; + _hopBytes = 1; // Clear regional channels (keeps only Public) and scope ChannelService.clearRegionalChannels(); @@ -2865,6 +3003,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { void updatePreferences(UserPreferences preferences) { debugLog('[APP] Preferences updated: externalAntennaSet=${preferences.externalAntennaSet}, ' 'externalAntenna=${preferences.externalAntenna}, autoPowerSet=${preferences.autoPowerSet}'); + _preferences = preferences; // Clear restored flag — user is making a manual choice now diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index 9be5eed..2906297 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -152,6 +152,15 @@ class _ConnectionScreenState extends State with WidgetsBinding // Show connected state if (appState.isConnected) { + // Show path hash mode warning popup if pending + final pathWarning = appState.pendingPathHashWarning; + if (pathWarning != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + _showPathHashWarning(context, pathWarning.hopBytes, pathWarning.reason); + appState.clearPathHashWarning(); + }); + } return _buildConnectedInfo(context, appState); } @@ -1636,6 +1645,84 @@ class _ConnectionScreenState extends State with WidgetsBinding }, ); } + + void _showPathHashWarning(BuildContext context, int hopBytes, String reason) { + if (reason == 'firmware_unsupported') { + // Firmware too old to support multi-byte paths + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.warning_amber, size: 24, color: Colors.amber), + SizedBox(width: 8), + Flexible(child: Text('Firmware Update Recommended')), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Your regional admin has enabled $hopBytes-byte path mode for this zone, ' + 'but your companion firmware does not support it.', + style: const TextStyle(fontSize: 14), + ), + const SizedBox(height: 12), + const Text( + 'The app will operate in 1-byte mode. Consider updating your companion ' + 'firmware to v1.14.0+ for more accurate repeater identification.', + style: TextStyle(fontSize: 13), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } else { + // Mode changed successfully + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.linear_scale, size: 24), + SizedBox(width: 8), + Text('Multi-Byte Paths Enabled'), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Your radio has been updated from 1-byte to $hopBytes-byte paths for this session ($reason).', + style: const TextStyle(fontSize: 14), + ), + const SizedBox(height: 12), + const Text( + 'If you disconnect unexpectedly (e.g., Bluetooth drops), your radio will remain ' + 'in multi-byte mode until you reconnect. A clean disconnect will restore your ' + 'radio to its previous setting.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } + } } class _DeviceListTile extends StatelessWidget { diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index dca29a8..afaad96 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -209,6 +209,53 @@ class _SettingsScreenState extends State { }, ), + // Path Bytes Setting + ListTile( + leading: const Icon(Icons.linear_scale), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Flexible(child: Text('Path Bytes', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showHopBytesInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + subtitle: appState.enforceHopBytes + ? const Text( + 'Enabled at the regional level', + style: TextStyle(color: Colors.amber), + ) + : (appState.isConnected && !appState.supportsMultiBytePaths) + ? const Text( + 'Firmware 1.14+ required', + style: TextStyle(color: Colors.amber), + ) + : !appState.isConnected + ? const Text('Must be connected to radio') + : const Text('Repeater ID size in path hops'), + trailing: DropdownButton( + value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, + underline: const SizedBox(), + items: const [ + DropdownMenuItem(value: 1, child: Text('1')), + DropdownMenuItem(value: 2, child: Text('2')), + DropdownMenuItem(value: 3, child: Text('3')), + ], + onChanged: (!appState.isConnected || isAutoMode || appState.enforceHopBytes || !appState.supportsMultiBytePaths) + ? null + : (value) { + if (value != null) appState.setHopBytes(value); + }, + ), + ), + // CARpeater Filter Setting SwitchListTile( secondary: const Icon(Icons.filter_alt), @@ -1040,6 +1087,51 @@ class _SettingsScreenState extends State { ); } + void _showHopBytesInfo(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.linear_scale, size: 24), + SizedBox(width: 8), + Text('Path Bytes'), + ], + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Controls how many bytes are used to identify each repeater in the packet path. ' + 'More bytes = more unique IDs, reducing collisions in large networks.', + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 12), + Text( + '\u2022 1 byte: 256 unique IDs (default)\n' + '\u2022 2 bytes: 65,536 unique IDs\n' + '\u2022 3 bytes: 16 million unique IDs', + style: TextStyle(fontSize: 13), + ), + SizedBox(height: 12), + Text( + 'Requires MeshCore firmware v1.14.0+. ' + 'RX always auto-detects the sender\'s byte size.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Got it'), + ), + ], + ), + ); + } + void _showIntervalSelector(BuildContext context, AppStateProvider appState) { final minInterval = appState.minModeInterval; var currentInterval = appState.preferences.autoPingInterval; @@ -1114,6 +1206,10 @@ class _SettingsScreenState extends State { } void _showRepeaterIdDialog(BuildContext context, AppStateProvider appState) { + final effectiveBytes = appState.effectiveHopBytes; + final maxHexChars = effectiveBytes * 2; + final hintText = 'F' * maxHexChars; + final controller = TextEditingController( text: appState.preferences.ignoreRepeaterId ?? '', ); @@ -1126,17 +1222,17 @@ class _SettingsScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Enter the repeater ID of your CARpeater (2 hex digits):'), + Text('Enter the repeater ID of your CARpeater ($maxHexChars hex digits):'), const SizedBox(height: 16), TextField( controller: controller, - decoration: const InputDecoration( + decoration: InputDecoration( labelText: 'CARpeater ID', - hintText: 'FF', + hintText: hintText, prefixText: '0x', - border: OutlineInputBorder(), + border: const OutlineInputBorder(), ), - maxLength: 2, + maxLength: maxHexChars, textCapitalization: TextCapitalization.characters, onChanged: (value) { // Keep only valid hex characters @@ -1167,8 +1263,10 @@ class _SettingsScreenState extends State { TextButton( onPressed: () { final value = controller.text.trim().toUpperCase(); + // Accept hex IDs of any valid even length (2, 4, or 6 chars) final isValidHex = value.isEmpty || - (value.length == 2 && RegExp(r'^[0-9A-F]{2}$').hasMatch(value)); + (value.length % 2 == 0 && value.length <= 6 && + RegExp(r'^[0-9A-F]+$').hasMatch(value)); if (isValidHex) { // Enable ignoreCarpeater when setting a repeater ID @@ -1181,7 +1279,7 @@ class _SettingsScreenState extends State { ); Navigator.pop(context); } else { - AppToast.warning(context, 'Invalid hex value. Use 2 digits (00-FF).'); + AppToast.warning(context, 'Invalid hex value. Use $maxHexChars hex digits.'); } }, child: const Text('Save'), diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 34bb60d..72d8300 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -44,6 +44,7 @@ class ApiService { bool _enforceHybrid = false; bool _enforceDiscDrop = false; int _minModeInterval = 15; + int _apiHopBytes = 1; /// Callback to get current GPS coordinates for heartbeat /// Returns (lat, lon) or null if GPS is not available @@ -64,6 +65,12 @@ class ApiService { /// Minimum auto-ping interval enforced by regional admin (seconds) int get minModeInterval => _minModeInterval; + /// Path hop bytes enforced by regional admin (1, 2, or 3) + int get apiHopBytes => _apiHopBytes; + + /// Whether hop bytes are enforced by regional admin (only 2 or 3 enforces) + bool get enforceHopBytes => _apiHopBytes > 1; + ApiService({http.Client? client}) : _client = client ?? http.Client(); /// Sanitize payload by removing sensitive fields for logging @@ -348,6 +355,17 @@ class ApiService { _minModeInterval = 15; } + // Parse hop_bytes from auth response + final hopBytes = data['hop_bytes']; + if (hopBytes is int && hopBytes >= 1 && hopBytes <= 3) { + _apiHopBytes = hopBytes; + if (_apiHopBytes > 1) { + debugLog('[API] Regional admin enforces $_apiHopBytes-byte paths'); + } + } else { + _apiHopBytes = 1; + } + // Note: Heartbeat is enabled by AppStateProvider when auto mode starts // (not on initial auth, since heartbeat is only for auto mode) } else if (reason == 'disconnect') { @@ -650,6 +668,7 @@ class ApiService { _enforceHybrid = false; _enforceDiscDrop = false; _minModeInterval = 15; + _apiHopBytes = 1; _heartbeatTimer?.cancel(); _heartbeatTimer = null; debugLog('[API] Session cleared'); diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index 339e406..5594b2f 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -17,11 +17,13 @@ class DeviceQueryResponse { final int protocolVersion; final String manufacturer; final String? firmwareBuildDate; // Added in protocol v8 + final int? pathHashMode; // 0=1-byte, 1=2-byte, 2=3-byte (null if old firmware, v10+) const DeviceQueryResponse({ required this.protocolVersion, required this.manufacturer, this.firmwareBuildDate, + this.pathHashMode, }); } @@ -438,17 +440,40 @@ class MeshCoreConnection { // Protocol v7+ format reader.readBytes(6); // skip reserved bytes final buildDate = reader.readCString(12); // e.g. "04-Jan-2026" - final manufacturerModel = reader.readString(); // remainder of frame - + + // Read manufacturer model as CString(40) — fixed-length null-terminated + final manufacturerModel = reader.readCString(40); + + // Parse additional fields from v9+ firmware + int? pathHashMode; + if (reader.remainingBytesCount > 0) { + // FIRMWARE_VERSION: 20 bytes (skip) + if (reader.remainingBytesCount >= 20) { + reader.readBytes(20); // firmware version string + } + + // client_repeat: 1 byte (v9+, skip) + if (reader.remainingBytesCount >= 1) { + reader.readByte(); // client_repeat + } + + // path_hash_mode: 1 byte (v10+) + if (reader.remainingBytesCount >= 1) { + pathHashMode = reader.readByte(); + debugLog('[CONN] Device path hash mode: $pathHashMode (${pathHashMode + 1}-byte hops)'); + } + } + debugLog('[CONN] Build date: $buildDate'); debugLog('[CONN] Manufacturer model: $manufacturerModel'); - + final response = DeviceQueryResponse( protocolVersion: firmwareVer, manufacturer: manufacturerModel, firmwareBuildDate: buildDate, + pathHashMode: pathHashMode, ); - + _deviceQueryCompleter?.complete(response); _deviceQueryCompleter = null; } else { @@ -1054,6 +1079,17 @@ class MeshCoreConnection { debugLog('[CONN] Stopped battery polling'); } + /// Set path hash mode on the radio + /// mode: 0=1-byte, 1=2-byte, 2=3-byte (persisted in radio prefs) + Future setPathHashMode(int mode) async { + final data = BufferWriter(); + data.writeByte(CommandCodes.setPathHashMode); // 61 (0x3D) + data.writeByte(0); // reserved + data.writeByte(mode); // 0=1-byte, 1=2-byte, 2=3-byte + await _sendToRadio(data); + debugLog('[CONN] Sent setPathHashMode: mode=$mode (${mode + 1}-byte hops)'); + } + /// Reboot device Future reboot() async { final data = BufferWriter(); diff --git a/lib/services/meshcore/packet_metadata.dart b/lib/services/meshcore/packet_metadata.dart index b3fc743..a6dcc0a 100644 --- a/lib/services/meshcore/packet_metadata.dart +++ b/lib/services/meshcore/packet_metadata.dart @@ -8,31 +8,31 @@ import 'protocol_constants.dart'; class PacketMetadata { /// Original raw packet bytes final Uint8List raw; - + /// Packet header byte (contains route type, payload type, version) final int header; - + /// Route type (FLOOD=0x01, DIRECT=0x02) final int routeType; - - /// Number of hops in path - final int pathLength; - - /// Raw path bytes (repeater IDs) + + /// Raw pathLen byte (encodes both hash size and hop count) + final int pathLenRaw; + + /// Number of bytes per hop hash (1, 2, 3, or 4) + final int pathHashSize; + + /// Number of hops in path (0-63) + final int pathHashCount; + + /// Raw path bytes (repeater IDs, length = pathHashCount * pathHashSize) final Uint8List pathBytes; - - /// First hop (first repeater ID) - used for TX tracking - final int? firstHop; - - /// Last hop (last repeater ID) - used for RX logging - final int? lastHop; - + /// Signal-to-noise ratio (dB) final double snr; - + /// Received signal strength indicator (dBm) final int rssi; - + /// Encrypted payload (after header + path) final Uint8List encryptedPayload; @@ -40,17 +40,17 @@ class PacketMetadata { required this.raw, required this.header, required this.routeType, - required this.pathLength, + required this.pathLenRaw, + required this.pathHashSize, + required this.pathHashCount, required this.pathBytes, - required this.firstHop, - required this.lastHop, required this.snr, required this.rssi, required this.encryptedPayload, }); /// Parse packet metadata from BLE LogRxData event - /// + /// /// Event structure: /// ```dart /// { @@ -61,21 +61,21 @@ class PacketMetadata { /// ``` factory PacketMetadata.fromLogRxData(Map data) { debugLog('[RX PARSE] Starting metadata parsing'); - + final Uint8List raw = data['raw'] as Uint8List; final double snr = (data['lastSnr'] as num).toDouble(); final int rssi = data['lastRssi'] as int; - + // Dump raw packet for debugging final rawHex = raw.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()).join(' '); debugLog('[RX PARSE] RAW Packet (${raw.length} bytes): $rawHex'); - + // Extract header byte from raw[0] final int header = raw[0]; final int routeType = header & PacketHeader.routeMask; - + debugLog('[RX PARSE] Header: 0x${header.toRadixString(16).padLeft(2, '0')}, Route type: $routeType'); - + // Calculate offset for Path Length based on route type // Reference: wardrive.js lines 3168-3173 int pathLengthOffset = 1; @@ -83,42 +83,44 @@ class PacketMetadata { // TransportFlood or TransportDirect - has 4-byte transport codes pathLengthOffset = 5; } - - // Extract path length from calculated offset - final int pathLength = raw[pathLengthOffset]; - - debugLog('[RX PARSE] Path length offset: $pathLengthOffset, Path length: $pathLength'); - + + // Extract raw pathLen byte and decode multi-byte path encoding + // pathHashSize = (pathLen >> 6) + 1 → 1, 2, 3, or 4 + // pathHashCount = pathLen & 63 → 0-63 hops + final int pathLenRaw = raw[pathLengthOffset]; + final int pathHashSize = (pathLenRaw >> 6) + 1; + final int pathHashCount = pathLenRaw & 63; + final int pathByteLen = pathHashCount * pathHashSize; + + debugLog('[RX PARSE] Path length offset: $pathLengthOffset, pathLenRaw: 0x${pathLenRaw.toRadixString(16).padLeft(2, '0')}, ' + 'pathHashSize: $pathHashSize bytes/hop, pathHashCount: $pathHashCount hops, pathByteLen: $pathByteLen'); + // Path data starts after path length byte final int pathDataOffset = pathLengthOffset + 1; final Uint8List pathBytes = raw.sublist( pathDataOffset, - (pathDataOffset + pathLength).clamp(0, raw.length), + (pathDataOffset + pathByteLen).clamp(0, raw.length), ); - - // Derive first and last hops - final int? firstHop = pathBytes.isNotEmpty ? pathBytes.first : null; - final int? lastHop = pathBytes.isNotEmpty ? pathBytes.last : null; - + // Extract encrypted payload after path data - final int payloadOffset = pathDataOffset + pathLength; + final int payloadOffset = pathDataOffset + pathByteLen; final Uint8List encryptedPayload = raw.sublist(payloadOffset); - + debugLog('[RX PARSE] Parsed metadata: header=0x${header.toRadixString(16).padLeft(2, '0')}, ' - 'pathLength=$pathLength, ' - 'firstHop=${firstHop != null ? '0x${firstHop.toRadixString(16).padLeft(2, '0')}' : 'null'}, ' - 'lastHop=${lastHop != null ? '0x${lastHop.toRadixString(16).padLeft(2, '0')}' : 'null'}, ' + 'pathHashSize=$pathHashSize, pathHashCount=$pathHashCount, ' + 'firstHop=${pathHashCount > 0 ? _bytesToHexStatic(pathBytes.sublist(0, pathHashSize)) : 'null'}, ' + 'lastHop=${pathHashCount > 0 ? _bytesToHexStatic(pathBytes.sublist(pathBytes.length - pathHashSize)) : 'null'}, ' 'SNR=$snr, RSSI=$rssi, ' 'payload=${encryptedPayload.length} bytes'); - + return PacketMetadata( raw: raw, header: header, routeType: routeType, - pathLength: pathLength, + pathLenRaw: pathLenRaw, + pathHashSize: pathHashSize, + pathHashCount: pathHashCount, pathBytes: pathBytes, - firstHop: firstHop, - lastHop: lastHop, snr: snr, rssi: rssi, encryptedPayload: encryptedPayload, @@ -161,19 +163,42 @@ class PacketMetadata { } /// Get first hop as hex string (for TX tracking keys) + /// Returns multi-byte hex (2/4/6/8 chars depending on pathHashSize) String? get firstHopHex { - return firstHop?.toRadixString(16).padLeft(2, '0'); + if (pathHashCount == 0) return null; + return _bytesToHex(pathBytes.sublist(0, pathHashSize)); } /// Get last hop as hex string (for RX logging keys) + /// Returns multi-byte hex (2/4/6/8 chars depending on pathHashSize) String? get lastHopHex { - return lastHop?.toRadixString(16).padLeft(2, '0'); + if (pathHashCount == 0) return null; + return _bytesToHex(pathBytes.sublist(pathBytes.length - pathHashSize)); + } + + /// Get any hop by index as hex string + /// @param hopIndex 0-based hop index (0 = first hop) + String? getHopHex(int hopIndex) { + if (hopIndex < 0 || hopIndex >= pathHashCount) return null; + final offset = hopIndex * pathHashSize; + return _bytesToHex(pathBytes.sublist(offset, offset + pathHashSize)); + } + + /// Convert N bytes to uppercase hex string + String _bytesToHex(Uint8List bytes) { + return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join('').toUpperCase(); + } + + /// Static version for use in factory constructor + static String _bytesToHexStatic(Uint8List bytes) { + return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join('').toUpperCase(); } @override String toString() { return 'PacketMetadata(header=0x${header.toRadixString(16).padLeft(2, '0')}, ' - 'pathLength=$pathLength, firstHop=$firstHopHex, lastHop=$lastHopHex, ' + 'pathHashSize=$pathHashSize, pathHashCount=$pathHashCount, ' + 'firstHop=$firstHopHex, lastHop=$lastHopHex, ' 'SNR=$snr, RSSI=$rssi)'; } } diff --git a/lib/services/meshcore/packet_validator.dart b/lib/services/meshcore/packet_validator.dart index 7c11956..8cfd5d0 100644 --- a/lib/services/meshcore/packet_validator.dart +++ b/lib/services/meshcore/packet_validator.dart @@ -38,7 +38,7 @@ class PacketValidator { debugLog('[RX FILTER] ========== VALIDATING PACKET =========='); debugLog('[RX FILTER] Raw packet (${metadata.raw.length} bytes): $rawHex'); debugLog('[RX FILTER] Header: 0x${metadata.header.toRadixString(16).padLeft(2, '0')} | ' - 'PathLength: ${metadata.pathLength} | SNR: ${metadata.snr}'); + 'PathHashCount: ${metadata.pathHashCount} | SNR: ${metadata.snr}'); // VALIDATION 1: Check RSSI (carpeater filter) if (skipRssiCheck) { diff --git a/lib/services/meshcore/protocol_constants.dart b/lib/services/meshcore/protocol_constants.dart index 56f7f6c..3dee89f 100644 --- a/lib/services/meshcore/protocol_constants.dart +++ b/lib/services/meshcore/protocol_constants.dart @@ -69,6 +69,7 @@ class CommandCodes { static const int setFloodScope = 54; // 0x36 - CMD_SET_FLOOD_SCOPE static const int getStats = 56; // 0x38 static const int sendBinaryReq = 50; + static const int setPathHashMode = 61; // 0x3D - CMD_SET_PATH_HASH_MODE } /// Response codes received from device diff --git a/lib/services/meshcore/rx_logger.dart b/lib/services/meshcore/rx_logger.dart index aa8a116..9c464b3 100644 --- a/lib/services/meshcore/rx_logger.dart +++ b/lib/services/meshcore/rx_logger.dart @@ -73,7 +73,7 @@ class RxLogger { // VALIDATION: Check path length (need at least one hop) // Packets with no path are direct transmissions and don't provide repeater coverage info - if (metadata.pathLength == 0) { + if (metadata.pathHashCount == 0) { debugLog('[RX LOG] Ignoring: no path (direct transmission, not via repeater)'); return false; } @@ -84,21 +84,17 @@ class RxLogger { int? reportedRssi = metadata.rssi; // Extract LAST hop from path (the repeater that directly delivered to us) - // Mask to last byte only (0xFF) for consistent 2-character display - final lastHopId = metadata.lastHop! & 0xFF; - final lastHopHex = lastHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + final lastHopHex = metadata.lastHopHex!; // CARpeater check: the carpeater is co-located with us, so it only // appears as the last hop (the delivery repeater) on RX packets if (carpeaterPrefix != null && lastHopHex == carpeaterPrefix!.toUpperCase()) { - if (metadata.pathLength < 2) { + if (metadata.pathHashCount < 2) { debugLog('[RX LOG] CARpeater pass-through: single-hop, dropping'); return false; } // Second-to-last hop = the real repeater that forwarded to our carpeater - final secondToLastIdx = metadata.pathLength - 2; - final underlyingHopId = metadata.pathBytes[secondToLastIdx] & 0xFF; - repeaterId = underlyingHopId.toRadixString(16).padLeft(2, '0').toUpperCase(); + repeaterId = metadata.getHopHex(metadata.pathHashCount - 2)!; carpeaterStripped = true; reportedSnr = null; reportedRssi = null; @@ -141,7 +137,7 @@ class RxLogger { } debugLog('[RX LOG] Packet heard via ${carpeaterStripped ? 'underlying' : 'last'} hop: $repeaterId, ' - 'SNR=$reportedSnr, path_length=${metadata.pathLength}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); + 'SNR=$reportedSnr, path_length=${metadata.pathHashCount}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); debugLog('[RX LOG] ✅ Packet validated and passed filter'); @@ -150,7 +146,7 @@ class RxLogger { repeaterId: repeaterId, snr: reportedSnr, rssi: reportedRssi, - pathLength: metadata.pathLength, + pathLength: metadata.pathHashCount, header: metadata.header, lat: gpsLocation.lat, lon: gpsLocation.lon, @@ -164,7 +160,7 @@ class RxLogger { repeaterId: repeaterId, snr: reportedSnr, rssi: reportedRssi, - pathLength: metadata.pathLength, + pathLength: metadata.pathHashCount, header: metadata.header, currentLocation: gpsLocation, metadata: metadata, diff --git a/lib/services/meshcore/tx_tracker.dart b/lib/services/meshcore/tx_tracker.dart index 925f199..21e63a4 100644 --- a/lib/services/meshcore/tx_tracker.dart +++ b/lib/services/meshcore/tx_tracker.dart @@ -112,14 +112,13 @@ class TxTracker { // VALIDATION STEP 1.5: Path length check (must have hops to identify repeater) // Moved before RSSI check so we can log the repeater ID on carpeater drops - if (metadata.pathLength == 0) { + if (metadata.pathHashCount == 0) { debugLog('[TX LOG] Ignoring: no path (direct transmission, not a repeater echo)'); return false; } // Extract first hop (first repeater) for use in validation and logging - final firstHopId = metadata.firstHop!; - var pathHex = firstHopId.toRadixString(16).padLeft(2, '0'); + var pathHex = metadata.firstHopHex!; // CARpeater pass-through: strip CARpeater hop and report underlying repeater bool carpeaterStripped = false; @@ -127,13 +126,12 @@ class TxTracker { int? reportedRssi = metadata.rssi; if (carpeaterPrefix != null && pathHex.toUpperCase() == carpeaterPrefix!.toUpperCase()) { - if (metadata.pathLength < 2) { + if (metadata.pathHashCount < 2) { debugLog('[TX LOG] CARpeater pass-through: single-hop, dropping'); return false; } - // Multi-hop: strip CARpeater, report underlying repeater - final underlyingHopId = metadata.pathBytes[1] & 0xFF; - final underlyingHex = underlyingHopId.toRadixString(16).padLeft(2, '0'); + // Multi-hop: strip CARpeater, report underlying repeater (second hop) + final underlyingHex = metadata.getHopHex(1)!; debugLog('[TX LOG] CARpeater pass-through: stripped $pathHex, reporting underlying repeater $underlyingHex'); pathHex = underlyingHex; carpeaterStripped = true; @@ -239,7 +237,7 @@ class TxTracker { // Path length and first hop already validated/extracted earlier (before RSSI check) debugLog('[PING] Repeater echo accepted: first_hop=$pathHex, SNR=$reportedSnr, ' - 'full_path_length=${metadata.pathLength}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); + 'full_path_length=${metadata.pathHashCount}${carpeaterStripped ? ' (CARpeater stripped)' : ''}'); // Deduplication: check if we already have this repeater bool isNewRepeater = false; diff --git a/lib/services/meshcore/unified_rx_handler.dart b/lib/services/meshcore/unified_rx_handler.dart index a15730e..6e92b74 100644 --- a/lib/services/meshcore/unified_rx_handler.dart +++ b/lib/services/meshcore/unified_rx_handler.dart @@ -71,7 +71,7 @@ class UnifiedRxHandler { debugLog('[UNIFIED RX] Packet received: ' 'header=0x${metadata.header.toRadixString(16)}, ' - 'pathLength=${metadata.pathLength}'); + 'pathHashSize=${metadata.pathHashSize}, pathHashCount=${metadata.pathHashCount}'); // Route to TX tracking if active (during 5s echo window) if (txTracker.isListening) { diff --git a/lib/widgets/repeater_id_chip.dart b/lib/widgets/repeater_id_chip.dart index b6c61ba..916f43d 100644 --- a/lib/widgets/repeater_id_chip.dart +++ b/lib/widgets/repeater_id_chip.dart @@ -10,11 +10,11 @@ import '../utils/distance_formatter.dart'; /// A styled repeater ID text with a dotted underline hint that it's tappable. /// -/// Displays the 2-char hex repeater ID in monospace style. Use together with -/// [RepeaterIdChip.showRepeaterPopup] on the parent row's `InkWell` so the -/// entire row is the tap target. +/// Displays the hex repeater ID (2/4/6 chars) in monospace style. Use together +/// with [RepeaterIdChip.showRepeaterPopup] on the parent row's `InkWell` so +/// the entire row is the tap target. class RepeaterIdChip extends StatelessWidget { - /// The 2-char hex repeater ID (e.g., "4e") + /// The hex repeater ID (e.g., "4E", "4F5D", "4F5D82") final String repeaterId; /// Font size for the ID text (11 for log screens, 13 for map popups) @@ -32,13 +32,16 @@ class RepeaterIdChip extends StatelessWidget { @override Widget build(BuildContext context) { + // Scale font size down for longer IDs (4+ chars) + final effectiveFontSize = repeaterId.length > 2 ? fontSize - 1.0 : fontSize; + final child = Row( mainAxisSize: MainAxisSize.min, children: [ Text( repeaterId, style: TextStyle( - fontSize: fontSize, + fontSize: effectiveFontSize, fontWeight: FontWeight.w600, fontFamily: 'monospace', color: Theme.of(context).colorScheme.onSurface, From 18226d6e346a47defbe4c948e0cc018a52538195 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 8 Mar 2026 12:57:55 -0400 Subject: [PATCH 20/57] Add hopBytes support and update repeater display logic - Introduced hopBytes property in Repeater model to manage bytes per hop. - Updated AppStateProvider to reflect changes in path hash mode. - Enhanced connection_screen and settings_screen to accommodate hopBytes settings. - Modified map_widget to display repeater markers based on hopBytes. - Improved repeater_id_chip to show hex ID badges with dynamic sizing. --- lib/models/repeater.dart | 17 +++++ lib/providers/app_state_provider.dart | 15 ++-- lib/screens/connection_screen.dart | 6 +- lib/screens/settings_screen.dart | 98 ++++++++++++++------------- lib/widgets/map_widget.dart | 74 ++++++++++++-------- lib/widgets/repeater_id_chip.dart | 62 ++++++++++------- 6 files changed, 164 insertions(+), 108 deletions(-) diff --git a/lib/models/repeater.dart b/lib/models/repeater.dart index cdf1867..bbf76bd 100644 --- a/lib/models/repeater.dart +++ b/lib/models/repeater.dart @@ -34,6 +34,9 @@ class Repeater { /// The repeater is active while `now < staleTime`. final int? staleTime; + /// Number of bytes per hop hash for this repeater's path (1, 2, or 3) + final int hopBytes; + const Repeater({ required this.id, required this.hexId, @@ -45,6 +48,7 @@ class Repeater { this.iata, this.createdAt, this.staleTime, + this.hopBytes = 1, }); /// Parse from JSON object in repeaters.json @@ -78,6 +82,7 @@ class Repeater { iata: json['iata'] as String?, createdAt: createdAt, staleTime: staleTime, + hopBytes: (json['hop_bytes'] as int?) ?? 1, ); } @@ -93,6 +98,7 @@ class Repeater { 'iata': iata, 'created_at': createdAt, 'stale_time': staleTime, + 'hop_bytes': hopBytes, }; } @@ -130,6 +136,17 @@ class Repeater { /// Check if the repeater has not been heard in the past 24 hours bool get isDead => !isActive; + /// Get display hex ID based on hop bytes (or override). + /// [overrideHopBytes] is used when regional admin enforces a byte size. + String displayHexId({int? overrideHopBytes}) { + final bytes = overrideHopBytes ?? hopBytes; + final hexChars = bytes * 2; // 1 byte = 2 hex chars + if (hexId.length >= hexChars) { + return hexId.substring(0, hexChars).toUpperCase(); + } + return id; // Fallback to short numeric ID + } + @override String toString() => 'Repeater(id=$id, name=$name, enabled=$isEnabled)'; } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 968a646..51c9854 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1801,6 +1801,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Need to change the radio's path hash mode try { await _meshCoreConnection!.setPathHashMode(effective - 1); + _hopBytes = effective; // Update runtime state to reflect new mode debugLog('[PATH] Set path hash mode: device was $deviceHopBytes-byte, now $effective-byte'); // Show warning popup if changing from 1-byte to multi-byte @@ -1838,17 +1839,19 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { return; } - final effective = effectiveHopBytes; - final deviceMode = _originalPathHashMode!; - final deviceHopBytes = deviceMode + 1; + final originalMode = _originalPathHashMode!; + final originalHopBytes = originalMode + 1; - if (effective != deviceHopBytes) { + // Compare current runtime mode against what the device had before we changed it + if (_hopBytes != originalHopBytes) { try { - await _meshCoreConnection?.setPathHashMode(deviceMode); - debugLog('[PATH] Restored path hash mode to original: $deviceHopBytes-byte'); + await _meshCoreConnection?.setPathHashMode(originalMode); + debugLog('[PATH] Restored path hash mode to original: $originalHopBytes-byte'); } catch (e) { debugError('[PATH] Failed to restore path hash mode: $e'); } + } else { + debugLog('[PATH] Path mode unchanged from original ($originalHopBytes-byte), no restore needed'); } _originalPathHashMode = null; _userChangedPathMode = false; diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index 2906297..bfa16f9 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -1693,7 +1693,7 @@ class _ConnectionScreenState extends State with WidgetsBinding children: [ Icon(Icons.linear_scale, size: 24), SizedBox(width: 8), - Text('Multi-Byte Paths Enabled'), + Flexible(child: Text('Multi-Byte Paths Enabled')), ], ), content: Column( @@ -1706,9 +1706,7 @@ class _ConnectionScreenState extends State with WidgetsBinding ), const SizedBox(height: 12), const Text( - 'If you disconnect unexpectedly (e.g., Bluetooth drops), your radio will remain ' - 'in multi-byte mode until you reconnect. A clean disconnect will restore your ' - 'radio to its previous setting.', + 'Your radio will remain in multi-byte mode until you change it.', style: TextStyle(fontSize: 13, color: Colors.amber), ), ], diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index afaad96..41ad04f 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -209,53 +209,6 @@ class _SettingsScreenState extends State { }, ), - // Path Bytes Setting - ListTile( - leading: const Icon(Icons.linear_scale), - title: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Flexible(child: Text('Path Bytes', overflow: TextOverflow.ellipsis)), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _showHopBytesInfo(context), - child: Icon( - Icons.info_outline, - size: 18, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ], - ), - subtitle: appState.enforceHopBytes - ? const Text( - 'Enabled at the regional level', - style: TextStyle(color: Colors.amber), - ) - : (appState.isConnected && !appState.supportsMultiBytePaths) - ? const Text( - 'Firmware 1.14+ required', - style: TextStyle(color: Colors.amber), - ) - : !appState.isConnected - ? const Text('Must be connected to radio') - : const Text('Repeater ID size in path hops'), - trailing: DropdownButton( - value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, - underline: const SizedBox(), - items: const [ - DropdownMenuItem(value: 1, child: Text('1')), - DropdownMenuItem(value: 2, child: Text('2')), - DropdownMenuItem(value: 3, child: Text('3')), - ], - onChanged: (!appState.isConnected || isAutoMode || appState.enforceHopBytes || !appState.supportsMultiBytePaths) - ? null - : (value) { - if (value != null) appState.setHopBytes(value); - }, - ), - ), - // CARpeater Filter Setting SwitchListTile( secondary: const Icon(Icons.filter_alt), @@ -347,6 +300,57 @@ class _SettingsScreenState extends State { ), ), + // Radio Settings section + const Divider(), + _buildSectionHeader(context, 'Radio Settings'), + + // Path Bytes Setting + ListTile( + leading: const Icon(Icons.linear_scale), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Flexible(child: Text('Path Bytes', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showHopBytesInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + subtitle: appState.enforceHopBytes + ? const Text( + 'Enabled at the regional level', + style: TextStyle(color: Colors.amber), + ) + : (appState.isConnected && !appState.supportsMultiBytePaths) + ? const Text( + 'Firmware 1.14+ required', + style: TextStyle(color: Colors.amber), + ) + : !appState.isConnected + ? const Text('Must be connected to radio') + : const Text('Repeater ID size in path hops'), + trailing: DropdownButton( + value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, + underline: const SizedBox(), + items: const [ + DropdownMenuItem(value: 1, child: Text('1')), + DropdownMenuItem(value: 2, child: Text('2')), + DropdownMenuItem(value: 3, child: Text('3')), + ], + onChanged: (!appState.isConnected || isAutoMode || appState.enforceHopBytes || !appState.supportsMultiBytePaths) + ? null + : (value) { + if (value != null) appState.setHopBytes(value); + }, + ), + ), + // Background Mode - for "Always" location permission (iOS and Android) if (!kIsWeb) ...[ const Divider(), diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index c478080..c719458 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -688,7 +688,10 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // Repeater markers (magenta circles with ID) MarkerLayer( - markers: _buildRepeaterMarkers(appState.repeaters), + markers: _buildRepeaterMarkers( + appState.repeaters, + appState.enforceHopBytes ? appState.effectiveHopBytes : null, + ), ), // Current position marker (car icon) @@ -1634,23 +1637,31 @@ class _MapWidgetState extends State with TickerProviderStateMixin { return _repeaterMarkerColor; // Active (default) } - List _buildRepeaterMarkers(List repeaters) { + List _buildRepeaterMarkers(List repeaters, int? regionHopBytesOverride) { final duplicateIds = _getDuplicateRepeaterIds(repeaters); return repeaters.map((repeater) { final isDuplicate = duplicateIds.contains(repeater.id); final markerColor = _getRepeaterMarkerColor(repeater, isDuplicate); + // Display hex ID based on per-repeater hop_bytes (or regional admin override) + final displayId = repeater.displayHexId(overrideHopBytes: regionHopBytesOverride); + final isLongId = displayId.length > 2; + final markerWidth = displayId.length > 4 ? 48.0 : isLongId ? 40.0 : 28.0; + return Marker( point: LatLng(repeater.lat, repeater.lon), - width: 28, + width: markerWidth, height: 28, child: GestureDetector( - onTap: () => _showRepeaterDetails(repeater, isDuplicate: isDuplicate), + onTap: () => _showRepeaterDetails(repeater, isDuplicate: isDuplicate, regionHopBytesOverride: regionHopBytesOverride), child: Container( + padding: isLongId + ? const EdgeInsets.symmetric(horizontal: 4) + : EdgeInsets.zero, decoration: BoxDecoration( color: markerColor, - shape: BoxShape.circle, + borderRadius: BorderRadius.circular(14), border: Border.all(color: Colors.white, width: 2), boxShadow: const [ BoxShadow( @@ -1662,11 +1673,12 @@ class _MapWidgetState extends State with TickerProviderStateMixin { ), alignment: Alignment.center, child: Text( - repeater.id, - style: const TextStyle( - fontSize: 10, + displayId, + style: TextStyle( + fontSize: displayId.length > 4 ? 8 : isLongId ? 9 : 10, fontWeight: FontWeight.bold, color: Colors.white, + fontFamily: 'monospace', ), ), ), @@ -2414,7 +2426,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { } /// Show repeater details popup - void _showRepeaterDetails(Repeater repeater, {bool isDuplicate = false}) { + void _showRepeaterDetails(Repeater repeater, {bool isDuplicate = false, int? regionHopBytesOverride}) { // Determine icon badge color based on primary status final iconColor = _getRepeaterMarkerColor(repeater, isDuplicate); @@ -2448,25 +2460,33 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // Header with icon badge (containing ID) and name Row( children: [ - // Icon badge with ID (mirrors map marker) - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - color: iconColor, - shape: BoxShape.circle, - border: Border.all(color: Colors.white, width: 2), - ), - alignment: Alignment.center, - child: Text( - repeater.id, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white, + // Icon badge with hex ID (mirrors map marker) + Builder(builder: (context) { + final displayId = repeater.displayHexId(overrideHopBytes: regionHopBytesOverride); + final isLongId = displayId.length > 2; + return Container( + constraints: const BoxConstraints(minWidth: 44), + height: 44, + padding: isLongId + ? const EdgeInsets.symmetric(horizontal: 8) + : EdgeInsets.zero, + decoration: BoxDecoration( + color: iconColor, + borderRadius: BorderRadius.circular(22), + border: Border.all(color: Colors.white, width: 2), ), - ), - ), + alignment: Alignment.center, + child: Text( + displayId, + style: TextStyle( + fontSize: isLongId ? 13 : 16, + fontWeight: FontWeight.bold, + color: Colors.white, + fontFamily: 'monospace', + ), + ), + ); + }), const SizedBox(width: 12), Expanded( child: Text( diff --git a/lib/widgets/repeater_id_chip.dart b/lib/widgets/repeater_id_chip.dart index 916f43d..6d25d4d 100644 --- a/lib/widgets/repeater_id_chip.dart +++ b/lib/widgets/repeater_id_chip.dart @@ -32,8 +32,12 @@ class RepeaterIdChip extends StatelessWidget { @override Widget build(BuildContext context) { - // Scale font size down for longer IDs (4+ chars) - final effectiveFontSize = repeaterId.length > 2 ? fontSize - 1.0 : fontSize; + // Scale font size down for longer IDs + final effectiveFontSize = repeaterId.length > 4 + ? fontSize - 2.0 // 6-char IDs (3-byte) + : repeaterId.length > 2 + ? fontSize - 1.0 // 4-char IDs (2-byte) + : fontSize; // 2-char IDs (1-byte) final child = Row( mainAxisSize: MainAxisSize.min, @@ -127,10 +131,11 @@ class RepeaterIdChip extends StatelessWidget { }); } + final regionOverride = appState.enforceHopBytes ? appState.effectiveHopBytes : null; content = Column( mainAxisSize: MainAxisSize.min, children: matches - .map((r) => _buildRepeaterRow(context, r, position: position)) + .map((r) => _buildRepeaterRow(context, r, position: position, regionHopBytesOverride: regionOverride)) .toList(), ); } @@ -191,6 +196,7 @@ class RepeaterIdChip extends StatelessWidget { BuildContext context, Repeater repeater, { Position? position, + int? regionHopBytesOverride, }) { final isActive = repeater.isActive; final badgeColor = isActive ? Colors.green : Colors.grey; @@ -221,27 +227,8 @@ class RepeaterIdChip extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ - // Colored circle badge - Container( - width: 28, - height: 28, - decoration: BoxDecoration( - color: badgeColor, - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: Text( - repeater.hexId.length >= 2 - ? repeater.hexId.substring(0, 2).toUpperCase() - : repeater.hexId.toUpperCase(), - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.white, - fontFamily: 'monospace', - ), - ), - ), + // Colored badge — circle for short IDs, pill for longer + _buildHexBadge(repeater.displayHexId(overrideHopBytes: regionHopBytesOverride), badgeColor), const SizedBox(width: 12), // Repeater name + distance subtitle Expanded( @@ -305,4 +292,31 @@ class RepeaterIdChip extends StatelessWidget { ), ); } + + /// Build a hex ID badge — circle for 2-char, pill for longer IDs + static Widget _buildHexBadge(String displayId, Color color) { + final isLong = displayId.length > 2; + + return Container( + constraints: const BoxConstraints(minWidth: 28), + height: 28, + padding: isLong + ? const EdgeInsets.symmetric(horizontal: 5) + : EdgeInsets.zero, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Text( + displayId, + style: TextStyle( + fontSize: displayId.length > 4 ? 8 : 10, + fontWeight: FontWeight.bold, + color: Colors.white, + fontFamily: 'monospace', + ), + ), + ); + } } From a62539cb44d64321c6036b5299d88c990de012fb Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 8 Mar 2026 13:13:45 -0400 Subject: [PATCH 21/57] Refactor settings screen theme and unit toggles to use SwitchListTile; improve UI text for clarity --- lib/screens/settings_screen.dart | 73 ++++++++++++++------------------ lib/widgets/map_widget.dart | 10 ++++- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 41ad04f..77e6378 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -109,31 +109,27 @@ class _SettingsScreenState extends State { children: [ // Appearance section _buildSectionHeader(context, 'Appearance'), - ListTile( - leading: Icon( + SwitchListTile( + secondary: Icon( prefs.themeMode == 'dark' ? Icons.dark_mode : Icons.light_mode, ), title: const Text('Theme'), subtitle: Text(prefs.themeMode == 'dark' ? 'Dark mode' : 'Light mode'), - trailing: Switch( - value: prefs.themeMode == 'dark', - onChanged: (isDark) { - appState.setThemeMode(isDark ? 'dark' : 'light'); - }, - ), + value: prefs.themeMode == 'dark', + onChanged: (isDark) { + appState.setThemeMode(isDark ? 'dark' : 'light'); + }, ), - ListTile( - leading: Icon( + SwitchListTile( + secondary: Icon( prefs.isImperial ? Icons.square_foot : Icons.straighten, ), title: const Text('Units'), subtitle: Text(prefs.isImperial ? 'Imperial (mi, ft)' : 'Metric (km, m)'), - trailing: Switch( - value: prefs.isImperial, - onChanged: (isImperial) { - appState.setUnitSystem(isImperial ? 'imperial' : 'metric'); - }, - ), + value: prefs.isImperial, + onChanged: (isImperial) { + appState.setUnitSystem(isImperial ? 'imperial' : 'metric'); + }, ), const Divider(), @@ -156,7 +152,7 @@ class _SettingsScreenState extends State { secondary: const Icon(Icons.compare_arrows), title: Row( children: [ - const Text('Hybrid Mode'), + const Flexible(child: Text('Hybrid Mode', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), GestureDetector( onTap: () => _showHybridModeInfo(context), @@ -185,7 +181,7 @@ class _SettingsScreenState extends State { secondary: const Icon(Icons.signal_wifi_off), title: Row( children: [ - const Text('Discovery Drop'), + const Flexible(child: Text('Discovery Drop', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), GestureDetector( onTap: () => _showDiscDropInfo(context), @@ -199,7 +195,7 @@ class _SettingsScreenState extends State { ), subtitle: appState.enforceDiscDrop ? const Text( - 'Enabled by Regional Admin', + 'Set by Regional Admin — reports dead zones for network analysis.', style: TextStyle(color: Colors.amber), ) : const Text('Count failed discoveries as failed pings'), @@ -280,19 +276,18 @@ class _SettingsScreenState extends State { // Lock indicator if (isAutoMode) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: [ - Icon(Icons.lock, size: 16, color: Colors.orange.shade700), - const SizedBox(width: 8), + Icon(Icons.lock, size: 16, color: Colors.amber), + SizedBox(width: 8), Expanded( child: Text( 'Settings locked during auto-ping mode', style: TextStyle( fontSize: 12, - color: Colors.orange.shade700, - fontStyle: FontStyle.italic, + color: Colors.amber, ), ), ), @@ -308,7 +303,6 @@ class _SettingsScreenState extends State { ListTile( leading: const Icon(Icons.linear_scale), title: Row( - mainAxisSize: MainAxisSize.min, children: [ const Flexible(child: Text('Path Bytes', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), @@ -324,7 +318,7 @@ class _SettingsScreenState extends State { ), subtitle: appState.enforceHopBytes ? const Text( - 'Enabled at the regional level', + 'Set by Regional Admin — larger IDs reduce collisions in your region.', style: TextStyle(color: Colors.amber), ) : (appState.isConnected && !appState.supportsMultiBytePaths) @@ -333,7 +327,10 @@ class _SettingsScreenState extends State { style: TextStyle(color: Colors.amber), ) : !appState.isConnected - ? const Text('Must be connected to radio') + ? const Text( + 'Connect to radio to configure', + style: TextStyle(color: Colors.amber), + ) : const Text('Repeater ID size in path hops'), trailing: DropdownButton( value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, @@ -408,29 +405,23 @@ class _SettingsScreenState extends State { const Divider(), - // Device Info section - _buildSectionHeader(context, 'Device'), + // About section + _buildSectionHeader(context, 'About'), ListTile( leading: const Icon(Icons.perm_identity), title: const Text('Device ID'), subtitle: Text(appState.deviceId), ), - - const Divider(), - - // About section - _buildSectionHeader(context, 'About'), const ListTile( leading: Icon(Icons.info_outline), title: Text(AppConstants.appName), + subtitle: Text('Mesh network coverage mapper'), ), - GestureDetector( + ListTile( + leading: const Icon(Icons.new_releases_outlined), + title: const Text('Version'), + subtitle: Text(AppConstants.appVersion), onTap: () => _onVersionTap(appState), - child: ListTile( - leading: const Icon(Icons.new_releases_outlined), - title: const Text('Version'), - subtitle: Text(AppConstants.appVersion), - ), ), ListTile( leading: const Icon(Icons.feedback_outlined), diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index c719458..d616bbc 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -1646,9 +1646,17 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // Display hex ID based on per-repeater hop_bytes (or regional admin override) final displayId = repeater.displayHexId(overrideHopBytes: regionHopBytesOverride); + final effectiveBytes = regionHopBytesOverride ?? repeater.hopBytes; final isLongId = displayId.length > 2; final markerWidth = displayId.length > 4 ? 48.0 : isLongId ? 40.0 : 28.0; + // Shape varies by hop bytes: 1=square, 2=rounded rect, 3=more rounded + final borderRadius = effectiveBytes >= 3 + ? BorderRadius.circular(8) + : effectiveBytes == 2 + ? BorderRadius.circular(6) + : BorderRadius.circular(4); + return Marker( point: LatLng(repeater.lat, repeater.lon), width: markerWidth, @@ -1661,7 +1669,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { : EdgeInsets.zero, decoration: BoxDecoration( color: markerColor, - borderRadius: BorderRadius.circular(14), + borderRadius: borderRadius, border: Border.all(color: Colors.white, width: 2), boxShadow: const [ BoxShadow( From 25739ed653e212fda31c388923775ddd90e11173 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 8 Mar 2026 13:38:08 -0400 Subject: [PATCH 22/57] Repeater markers now rotate with the map and stay upright Co-Authored-By: Claude Opus 4.6 --- lib/widgets/map_widget.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index d616bbc..7448452 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -686,8 +686,9 @@ class _MapWidgetState extends State with TickerProviderStateMixin { markers: _buildDiscMarkers(appState.discLogEntries, appState.discDropEnabled), ), - // Repeater markers (magenta circles with ID) + // Repeater markers (magenta with ID, rotate with map) MarkerLayer( + rotate: true, markers: _buildRepeaterMarkers( appState.repeaters, appState.enforceHopBytes ? appState.effectiveHopBytes : null, From 8f061ddc7c162a55f6fe3a393583f9ebead82484 Mon Sep 17 00:00:00 2001 From: Rob Ekl Date: Sun, 8 Mar 2026 11:51:21 -0600 Subject: [PATCH 23/57] Prevent duplicate GPS stream subscriptions on restart (#6) Clean fix, guarding startWatching() against stacked subscriptions. Placement at the top of the method is correct (before any early returns). Pattern matches existing subscription management elsewhere in the codebase. --- lib/services/gps_service.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/services/gps_service.dart b/lib/services/gps_service.dart index 1535a62..1c30249 100644 --- a/lib/services/gps_service.dart +++ b/lib/services/gps_service.dart @@ -161,6 +161,14 @@ class GpsService { Future startWatching() async { debugLog('[GPS] startWatching() called, current status: $_status'); + // Ensure only one active position stream subscription exists. + // startWatching() can be called multiple times (e.g. after permission flow). + if (_positionSubscription != null) { + debugLog('[GPS] Existing position subscription found, restarting watcher'); + await _positionSubscription?.cancel(); + _positionSubscription = null; + } + // Check if location services are enabled first (system-level setting) final serviceEnabled = await isLocationServiceEnabled(); debugLog('[GPS] Location services check: enabled=$serviceEnabled'); From c8f0d71a37833fbb98444a65bc6b2c5bc0eba3f9 Mon Sep 17 00:00:00 2001 From: Rob Ekl Date: Sun, 8 Mar 2026 11:51:36 -0600 Subject: [PATCH 24/57] Own and dispose app-level stream subscriptions (#7) Good catch. These three stream subscriptions were the last unowned listeners in AppStateProvider. The fix mirrors the existing pattern used for _adapterStateSubscription, _logRxDataSubscription, _noiseFloorSubscription, and _batterySubscription. Clean and consistent. --- lib/providers/app_state_provider.dart | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 51c9854..2049c76 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -104,6 +104,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Bluetooth adapter state (on/off) BluetoothAdapterState _bluetoothAdapterState = BluetoothAdapterState.unknown; StreamSubscription? _adapterStateSubscription; + StreamSubscription? _connectionSubscription; + StreamSubscription? _gpsStatusSubscription; + StreamSubscription? _gpsPositionSubscription; // GPS state GpsStatus _gpsStatus = GpsStatus.permissionDenied; @@ -558,7 +561,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Listen to Bluetooth connection changes debugLog('[INIT] Setting up BLE connection listener...'); - _bluetoothService.connectionStream.listen((status) async { + await _connectionSubscription?.cancel(); + _connectionSubscription = _bluetoothService.connectionStream.listen((status) async { _connectionStatus = status; if (status == ConnectionStatus.disconnected) { // Check if this is an unexpected disconnect during active wardriving @@ -582,7 +586,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Listen to GPS changes debugLog('[INIT] Setting up GPS status listener...'); - _gpsService.statusStream.listen((status) { + await _gpsStatusSubscription?.cancel(); + _gpsStatusSubscription = _gpsService.statusStream.listen((status) { final previousStatus = _gpsStatus; _gpsStatus = status; @@ -607,7 +612,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[INIT] Initial GPS status: $_gpsStatus'); debugLog('[INIT] Setting up GPS position listener...'); - _gpsService.positionStream.listen((position) async { + await _gpsPositionSubscription?.cancel(); + _gpsPositionSubscription = _gpsService.positionStream.listen((position) async { _currentPosition = position; notifyListeners(); @@ -4345,6 +4351,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _isDisposed = true; WidgetsBinding.instance.removeObserver(this); _adapterStateSubscription?.cancel(); + _connectionSubscription?.cancel(); + _gpsStatusSubscription?.cancel(); + _gpsPositionSubscription?.cancel(); _logRxDataSubscription?.cancel(); _noiseFloorSubscription?.cancel(); _batterySubscription?.cancel(); From 4d41d432b785f2d18caf35d7aa524cd5cfc211c2 Mon Sep 17 00:00:00 2001 From: Rob Ekl Date: Sun, 8 Mar 2026 11:51:56 -0600 Subject: [PATCH 25/57] Fix mobile BLE scan stream completion and cleanup (#8) Fixes a real issue: the scan stream had no termination path, which could leave callers hanging. The three cleanup paths (natural stop, manual stop, finally) cover all cases well. The identical() check on _scanController is a nice detail for rapid re-scan scenarios. Minor note: the unawaited watcher on isScanning could theoretically fire before scan results arrive if isScanning briefly emits false during startup, but the !controller.isClosed guards prevent any actual breakage. --- lib/services/bluetooth/mobile_bluetooth.dart | 29 +++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/services/bluetooth/mobile_bluetooth.dart b/lib/services/bluetooth/mobile_bluetooth.dart index 6131f83..d279477 100644 --- a/lib/services/bluetooth/mobile_bluetooth.dart +++ b/lib/services/bluetooth/mobile_bluetooth.dart @@ -46,6 +46,7 @@ class MobileBluetoothService implements BluetoothService { StreamSubscription? _connectionStateSubscription; StreamSubscription? _notificationSubscription; StreamSubscription? _scanSubscription; + StreamController? _scanController; // Store scanned device info for use in connect() // This preserves the device name from scan results @@ -183,10 +184,15 @@ class MobileBluetoothService implements BluetoothService { @override Stream scanForDevices({Duration? timeout}) async* { final controller = StreamController(); + _scanController = controller; _updateStatus(ConnectionStatus.scanning); try { + // Ensure any previous scan stream is closed before starting a new one + await _scanSubscription?.cancel(); + _scanSubscription = null; + // Start scanning with filter for MeshCore service UUID await fbp.FlutterBluePlus.startScan( withServices: [fbp.Guid(BleUuids.serviceUuid)], @@ -208,14 +214,30 @@ class MobileBluetoothService implements BluetoothService { ); // Store device info for use in connect() - preserves name from scan _scannedDevices[device.id] = device; - controller.add(device); + if (!controller.isClosed) { + controller.add(device); + } } }); + // Complete stream when scan naturally stops (timeout or platform stop) + unawaited(() async { + await fbp.FlutterBluePlus.isScanning.where((isScanning) => !isScanning).first; + if (!controller.isClosed) { + await controller.close(); + } + }()); + yield* controller.stream; } finally { await _scanSubscription?.cancel(); _scanSubscription = null; + if (!controller.isClosed) { + await controller.close(); + } + if (identical(_scanController, controller)) { + _scanController = null; + } } } @@ -224,6 +246,11 @@ class MobileBluetoothService implements BluetoothService { await fbp.FlutterBluePlus.stopScan(); await _scanSubscription?.cancel(); _scanSubscription = null; + final scanController = _scanController; + if (scanController != null && !scanController.isClosed) { + await scanController.close(); + } + _scanController = null; // NOTE: Do NOT fire 'disconnected' here. Stopping a scan is not a disconnection. // The status will be updated by connect() when a connection starts. // Firing 'disconnected' here causes a race condition where the queued event From 18330b529c169aa942fda9f8d59e9479ccc52dda Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 8 Mar 2026 21:30:20 -0400 Subject: [PATCH 26/57] Bump version to 1.2.0 and enhance authentication flow with staged public_key and contact_uri registration --- .build_version | 2 +- lib/providers/app_state_provider.dart | 106 +++++++++++++++++++++++--- lib/services/gps_service.dart | 6 ++ 3 files changed, 101 insertions(+), 13 deletions(-) diff --git a/.build_version b/.build_version index 524cb55..26aaba0 100644 --- a/.build_version +++ b/.build_version @@ -1 +1 @@ -1.1.1 +1.2.0 diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 2049c76..2d7a768 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -2700,33 +2700,115 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { return (success: false, error: _modeSwitchError); } - debugLog('[APP] Requesting auth for online mode'); - final result = await _apiService.requestAuth( + // ============================================================ + // STAGE 1: Try existing public_key authentication + // ============================================================ + debugLog('[APP] Stage 1: Attempting auth with public_key: ${_devicePublicKey!.substring(0, 16)}...'); + + final modelString = _meshCoreConnection?.deviceModel?.manufacturer ?? + _meshCoreConnection?.deviceInfo?.manufacturer ?? 'Unknown'; + + var result = await _apiService.requestAuth( reason: 'connect', publicKey: _devicePublicKey!, who: deviceName, appVersion: _appVersion, power: _preferences.powerLevel, iataCode: zoneCode ?? _preferences.iataCode, - model: _meshCoreConnection?.deviceModel?.manufacturer ?? - _meshCoreConnection?.deviceInfo?.manufacturer ?? 'Unknown', + model: modelString, lat: _currentPosition!.latitude, lon: _currentPosition!.longitude, accuracyMeters: _currentPosition!.accuracy, ); - if (result == null) { - debugError('[APP] Auth request failed: no response'); - _modeSwitchError = 'Unable to connect to server'; + // Check for maintenance mode + if (result != null && result['maintenance'] == true) { + _maintenanceMode = true; + _maintenanceMessage = result['maintenance_message'] as String?; + _maintenanceUrl = result['maintenance_url'] as String?; + debugLog('[MAINTENANCE] Auth returned maintenance: $_maintenanceMessage'); + _startMaintenancePolling(); + notifyListeners(); + _modeSwitchError = _maintenanceMessage ?? 'Service is under maintenance'; return (success: false, error: _modeSwitchError); } - if (result['success'] != true) { - final reason = result['reason'] as String?; - final message = result['message'] as String?; - debugError('[APP] Auth request failed: $reason - $message'); - _modeSwitchError = message ?? reason ?? 'Authentication failed'; + // Check if Stage 1 succeeded + if (result != null && result['success'] == true) { + debugLog('[APP] Stage 1 succeeded: authenticated via public_key'); + if (result['type'] != null) { + _authType = result['type'] as String; + debugLog('[APP] Auth type: $_authType'); + notifyListeners(); + } + } else if (result == null) { + // API unreachable (null = network/timeout error) + debugError('[APP] API unreachable - network error'); + _modeSwitchError = 'Unable to reach the MeshMapper server'; return (success: false, error: _modeSwitchError); + } else { + // Stage 1 failed — check if Stage 2 is worth attempting + debugLog('[APP] Stage 1 failed: ${result['message'] ?? 'Unknown error'}'); + + final stage1Reason = result['reason'] as String?; + if (stage1Reason == 'gps_inaccurate' || stage1Reason == 'gps_stale') { + debugError('[APP] Stage 1 failed for GPS reason ($stage1Reason), skipping Stage 2'); + _modeSwitchError = result['message'] as String? ?? 'GPS error'; + return (success: false, error: _modeSwitchError); + } + + // ============================================================ + // STAGE 2: Auth failed, attempt registration via signed contact_uri + // ============================================================ + debugLog('[APP] Stage 2: Attempting registration via contact_uri...'); + + String? contactUri; + try { + debugLog('[APP] Requesting signed contact URI from device...'); + contactUri = await _meshCoreConnection!.exportContact(); + debugLog('[APP] Received contact URI: ${contactUri.substring(0, 50)}...'); + } catch (e) { + debugError('[APP] Failed to get contact URI from device: $e'); + _modeSwitchError = 'Companion not found in backend and failed to register via API'; + return (success: false, error: _modeSwitchError); + } + + final registerResult = await _apiService.requestAuth( + reason: 'register', + contactUri: contactUri, + who: deviceName, + appVersion: _appVersion, + power: _preferences.powerLevel, + iataCode: zoneCode ?? _preferences.iataCode, + model: modelString, + lat: _currentPosition!.latitude, + lon: _currentPosition!.longitude, + accuracyMeters: _currentPosition!.accuracy, + ); + + if (registerResult == null) { + debugError('[APP] Stage 2 failed: network error (API unreachable)'); + _modeSwitchError = 'Unable to reach the MeshMapper server'; + return (success: false, error: _modeSwitchError); + } + + if (registerResult['success'] != true) { + final serverReason = registerResult['reason'] as String? ?? 'registration_failed'; + final serverMessage = registerResult['message'] as String?; + debugError('[APP] Stage 2 failed: $serverReason - ${serverMessage ?? 'no message'}'); + _modeSwitchError = serverMessage ?? 'Registration rejected by server'; + return (success: false, error: _modeSwitchError); + } + + // Registration successful + debugLog('[APP] Stage 2 succeeded: registered and authenticated'); + if (registerResult['type'] != null) { + _authType = registerResult['type'] as String; + debugLog('[APP] Auth type: $_authType'); + notifyListeners(); + } + + result = registerResult; } // 5. Auth successful - update state diff --git a/lib/services/gps_service.dart b/lib/services/gps_service.dart index 1c30249..a6c7084 100644 --- a/lib/services/gps_service.dart +++ b/lib/services/gps_service.dart @@ -202,6 +202,12 @@ class GpsService { } debugLog('[GPS] Starting position stream listener...'); + + // Cancel any existing subscription to prevent orphaned listeners + // (e.g. restartGpsAfterPermission() racing with _initialize()) + await _positionSubscription?.cancel(); + _positionSubscription = null; + _updateStatus(GpsStatus.searching); // Configure location settings for position stream From fb59acaf0a7ee8d6e3e38b7fec3345f321dd34fc Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 8 Mar 2026 21:55:46 -0400 Subject: [PATCH 27/57] - **Hive corruption fallback for ping queue:** When the `api_queue` Hive box fails to open (e.g. corruption), `_safeWrite()` was silently returning false and dropping all enqueued pings. A full wardrive session could complete with zero ping data uploaded, as all POSTs would be heartbeats only. Fixed by adding a `_memoryQueue` in-memory fallback: failed writes go to memory instead of being dropped, `_uploadBatch` drains both Hive and memory queues, `queueSize` reflects both, and all clear/disconnect/init paths also flush `_memoryQueue`. --- lib/providers/app_state_provider.dart | 57 ++++++++++- lib/services/api_queue_service.dart | 110 ++++++++++++++++------ lib/services/offline_session_service.dart | 7 ++ 3 files changed, 140 insertions(+), 34 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 2d7a768..a7d50bf 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -119,6 +119,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { DeviceModel? _deviceModel; String? _manufacturerString; String? _devicePublicKey; + String? _offlineContactUri; /// BLE device name (e.g., "MeshCore-MrAlders0n_Elecrow") String? get connectedDeviceName => _bluetoothService.connectedDevice?.name; @@ -1032,6 +1033,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (deviceName != null && deviceName.isNotEmpty && _devicePublicKey != null) { _saveLastConnectedDevice(deviceName, _devicePublicKey!); } + + // In offline mode, fetch signed contact URI for later registration during upload + if (_preferences.offlineMode && _meshCoreConnection != null) { + _meshCoreConnection!.exportContact().then((uri) { + _offlineContactUri = uri; + debugLog('[OFFLINE] Stored contact URI for offline session'); + }).catchError((e) { + debugWarn('[OFFLINE] Failed to get contact URI: $e'); + }); + } } notifyListeners(); }); @@ -2242,6 +2253,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _deviceModel = null; _manufacturerString = null; _devicePublicKey = null; + _offlineContactUri = null; _displayDeviceName = null; _antennaRestoredFromDevice = false; _preferences = _preferences.copyWith(externalAntenna: false, externalAntennaSet: false); @@ -2930,6 +2942,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { pings, devicePublicKey: _devicePublicKey, deviceName: offlineDeviceName, + contactUri: _offlineContactUri, ); debugLog('[APP] Saved offline session with ${pings.length} pings'); notifyListeners(); @@ -3023,13 +3036,49 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { offlineMode: true, ); - if (authResult == null || authResult['success'] != true) { - final reason = authResult?['reason'] as String? ?? 'unknown'; - debugError('[API] Offline upload auth failed: $reason'); + Map? effectiveAuth = authResult; + + if (authResult == null) { + debugError('[API] Offline upload auth failed: network error'); return OfflineUploadResult.authFailed; } - debugLog('[APP] Offline upload authenticated, session: ${authResult['session_id']}'); + if (authResult['success'] != true) { + final reason = authResult['reason'] as String? ?? 'unknown'; + debugLog('[API] Offline upload Stage 1 failed: $reason'); + + // Stage 2: If unknown_device and we have a stored contactUri, attempt registration + if (reason == 'unknown_device' && session.contactUri != null) { + debugLog('[APP] Stage 2: Attempting registration via stored contact URI...'); + final registerResult = await _apiService.requestAuth( + reason: 'register', + contactUri: session.contactUri, + who: deviceName, + appVersion: _appVersion, + power: _preferences.powerLevel, + iataCode: zoneCode ?? _preferences.iataCode, + model: 'Offline Upload', + lat: _currentPosition?.latitude, + lon: _currentPosition?.longitude, + accuracyMeters: _currentPosition?.accuracy, + offlineMode: true, + ); + + if (registerResult == null || registerResult['success'] != true) { + final regReason = registerResult?['reason'] as String? ?? 'unknown'; + debugError('[API] Offline upload Stage 2 registration failed: $regReason'); + return OfflineUploadResult.authFailed; + } + + debugLog('[APP] Stage 2 succeeded: device registered for offline upload'); + effectiveAuth = registerResult; + } else { + debugError('[API] Offline upload auth failed: $reason'); + return OfflineUploadResult.authFailed; + } + } + + debugLog('[APP] Offline upload authenticated, session: ${effectiveAuth!['session_id']}'); // Delay after auth before posting await Future.delayed(const Duration(seconds: 1)); diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index 89b040f..17b598f 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -29,6 +29,9 @@ class ApiQueueService { bool _isUploading = false; bool _isRecovering = false; + // In-memory fallback when Hive is corrupted/unavailable + final List _memoryQueue = []; + // Offline mode bool offlineMode = false; final List> _offlinePings = []; @@ -79,6 +82,7 @@ class ApiQueueService { debugError('[API QUEUE] Failed to clear stale items: $e - recovering'); await _recoverBox(); } + _memoryQueue.clear(); _rxBuffer.clear(); _offlinePings.clear(); @@ -207,8 +211,8 @@ class ApiQueueService { } } - /// Get current queue size - int get queueSize => _safeRead((box) => box.length, 0); + /// Get current queue size (Hive + in-memory fallback) + int get queueSize => _safeRead((box) => box.length, 0) + _memoryQueue.length; /// Enqueue a TX ping /// heardRepeats format: "4e(12.25),77(12.25)" or "None" @@ -236,8 +240,13 @@ class ApiQueueService { return; } - await _safeWrite((box) => box.add(item)); - debugLog('[API QUEUE] TX enqueued: $heardRepeats (queue size: $queueSize)'); + final wrote = await _safeWrite((box) => box.add(item)); + if (!wrote) { + _memoryQueue.add(item); + debugLog('[API QUEUE] TX enqueued (memory fallback): $heardRepeats (queue size: $queueSize)'); + } else { + debugLog('[API QUEUE] TX enqueued: $heardRepeats (queue size: $queueSize)'); + } onQueueUpdated?.call(queueSize); _pingFlushTimer?.cancel(); _pingFlushTimer = Timer(const Duration(seconds: 5), () { @@ -322,8 +331,13 @@ class ApiQueueService { return; } - await _safeWrite((box) => box.add(item)); - debugLog('[API QUEUE] DISC enqueued: $repeaterId ($nodeType) at $latitude, $longitude (queue size: $queueSize)'); + final wrote = await _safeWrite((box) => box.add(item)); + if (!wrote) { + _memoryQueue.add(item); + debugLog('[API QUEUE] DISC enqueued (memory fallback): $repeaterId ($nodeType) at $latitude, $longitude (queue size: $queueSize)'); + } else { + debugLog('[API QUEUE] DISC enqueued: $repeaterId ($nodeType) at $latitude, $longitude (queue size: $queueSize)'); + } onQueueUpdated?.call(queueSize); _pingFlushTimer?.cancel(); _pingFlushTimer = Timer(const Duration(seconds: 5), () { @@ -356,8 +370,13 @@ class ApiQueueService { return; } - await _safeWrite((box) => box.add(item)); - debugLog('[API QUEUE] DISC drop enqueued at $latitude, $longitude (queue size: $queueSize)'); + final wrote = await _safeWrite((box) => box.add(item)); + if (!wrote) { + _memoryQueue.add(item); + debugLog('[API QUEUE] DISC drop enqueued (memory fallback) at $latitude, $longitude (queue size: $queueSize)'); + } else { + debugLog('[API QUEUE] DISC drop enqueued at $latitude, $longitude (queue size: $queueSize)'); + } onQueueUpdated?.call(queueSize); _pingFlushTimer?.cancel(); _pingFlushTimer = Timer(const Duration(seconds: 5), () { @@ -386,10 +405,12 @@ class ApiQueueService { final bufferSize = _rxBuffer.length; _rxBuffer.clear(); - // Now add items to the box + // Now add items to the box (or memory fallback) for (final item in itemsToFlush) { final ok = await _safeWrite((box) => box.add(item)); - if (!ok) break; + if (!ok) { + _memoryQueue.add(item); + } } debugLog('[API QUEUE] Flushed ${itemsToFlush.length} RX items from $bufferSize repeaters to queue'); @@ -424,13 +445,17 @@ class ApiQueueService { await _uploadBatch(); } - /// Upload batch of queued items + /// Upload batch of queued items (from Hive box or in-memory fallback) Future _uploadBatch() async { if (_isUploading) { debugLog('[API QUEUE] Upload skipped: already uploading'); return; } - if (_safeRead((box) => box.isEmpty, true)) { + + final hiveEmpty = _safeRead((box) => box.isEmpty, true); + final memoryEmpty = _memoryQueue.isEmpty; + + if (hiveEmpty && memoryEmpty) { debugLog('[API QUEUE] Upload skipped: queue empty'); return; } @@ -438,15 +463,8 @@ class ApiQueueService { _isUploading = true; try { - // Log if TX items are waiting in hold period - final pendingTx = _safeRead((box) => box.values.where((item) => - item.type == 'TX' && !item.isUploadEligible).length, 0); - if (pendingTx > 0) { - debugLog('[API QUEUE] $pendingTx TX items still in hold period'); - } - - // Get items ready for upload (must pass retry, retry delay, AND upload eligibility checks) - final items = _safeRead((box) => box.values + // Collect items from both Hive and memory queue + final hiveItems = _safeRead((box) => box.values .where((item) => item.retryCount < _maxRetries && item.isReadyForRetry && @@ -454,6 +472,16 @@ class ApiQueueService { .take(_batchSize) .toList(), []); + final memoryItems = _memoryQueue + .where((item) => + item.retryCount < _maxRetries && + item.isReadyForRetry && + item.isUploadEligible) + .take(_batchSize - hiveItems.length) + .toList(); + + final items = [...hiveItems, ...memoryItems]; + if (items.isEmpty) { debugLog('[API QUEUE] Upload skipped: no items ready for upload'); _isUploading = false; @@ -469,30 +497,47 @@ class ApiQueueService { debugLog('[API QUEUE] Item ${i + 1}/${items.length}: type=${item.type}, external_antenna=${item.externalAntenna}'); } - debugLog('[API QUEUE] Uploading ${items.length} items...'); + final memoryCount = memoryItems.length; + if (memoryCount > 0) { + debugLog('[API QUEUE] Uploading ${items.length} items ($memoryCount from memory fallback)...'); + } else { + debugLog('[API QUEUE] Uploading ${items.length} items...'); + } // Attempt upload final result = await _apiService.uploadBatch(pings); if (result == UploadResult.success) { final uploadedCount = items.length; - // Remove successful items - for (final item in items) { - await item.delete(); + // Remove successful Hive items + for (final item in hiveItems) { + try { await item.delete(); } catch (_) {} + } + // Remove successful memory items + for (final item in memoryItems) { + _memoryQueue.remove(item); } debugLog('[API QUEUE] Upload SUCCESS: deleted $uploadedCount items'); onUploadSuccess?.call(uploadedCount); } else if (result == UploadResult.nonRetryable) { - // Data is permanently invalid (bad GPS, invalid request, etc.) — discard - for (final item in items) { - await item.delete(); + // Data is permanently invalid — discard + for (final item in hiveItems) { + try { await item.delete(); } catch (_) {} + } + for (final item in memoryItems) { + _memoryQueue.remove(item); } debugWarn('[API QUEUE] Discarded ${items.length} items (non-retryable error)'); } else { // Mark items as retried - for (final item in items) { + for (final item in hiveItems) { item.markRetried(); } + // Memory items: update retry fields directly (no Hive save) + for (final item in memoryItems) { + item.retryCount++; + item.lastRetryAt = DateTime.now(); + } debugLog('[API QUEUE] Upload FAILED: ${items.length} items marked for retry'); } @@ -522,6 +567,7 @@ class ApiQueueService { /// Clear all queued items Future clear() async { await _safeWrite((box) => box.clear()); + _memoryQueue.clear(); _rxBuffer.clear(); onQueueUpdated?.call(0); } @@ -542,6 +588,7 @@ class ApiQueueService { debugLog('[API QUEUE] Clearing $count items on disconnect (queue: $queueSize, rxBuffer: ${_rxBuffer.length})'); } await _safeWrite((box) => box.clear()); + _memoryQueue.clear(); _rxBuffer.clear(); onQueueUpdated?.call(0); } @@ -555,6 +602,7 @@ class ApiQueueService { debugLog('[API QUEUE] Clearing $count stale items before connect'); } await _safeWrite((box) => box.clear()); + _memoryQueue.clear(); _rxBuffer.clear(); onQueueUpdated?.call(0); @@ -567,10 +615,12 @@ class ApiQueueService { /// Get failed items (exceeded max retries) List get failedItems { - return _safeRead( + final hiveItems = _safeRead( (box) => box.values.where((item) => item.retryCount >= _maxRetries).toList(), [], ); + final memoryItems = _memoryQueue.where((item) => item.retryCount >= _maxRetries).toList(); + return [...hiveItems, ...memoryItems]; } /// Get accumulated offline pings and clear the accumulator diff --git a/lib/services/offline_session_service.dart b/lib/services/offline_session_service.dart index 282d911..3df1b90 100644 --- a/lib/services/offline_session_service.dart +++ b/lib/services/offline_session_service.dart @@ -12,6 +12,7 @@ class OfflineSession { final Map data; final String? devicePublicKey; // Device public key for auth during upload final String? deviceName; // Device name for display + final String? contactUri; // Signed contact URI for registration during upload final bool uploaded; // Track upload status OfflineSession({ @@ -21,6 +22,7 @@ class OfflineSession { required this.data, this.devicePublicKey, this.deviceName, + this.contactUri, this.uploaded = false, }); @@ -33,6 +35,7 @@ class OfflineSession { data: json['data'] as Map, devicePublicKey: json['devicePublicKey'] as String?, deviceName: json['deviceName'] as String?, + contactUri: json['contactUri'] as String?, uploaded: json['uploaded'] as bool? ?? false, ); } @@ -46,6 +49,7 @@ class OfflineSession { 'data': data, 'devicePublicKey': devicePublicKey, 'deviceName': deviceName, + 'contactUri': contactUri, 'uploaded': uploaded, }; } @@ -59,6 +63,7 @@ class OfflineSession { data: data, devicePublicKey: devicePublicKey, deviceName: deviceName, + contactUri: contactUri, uploaded: uploaded ?? this.uploaded, ); } @@ -141,6 +146,7 @@ class OfflineSessionService { List> pings, { String? devicePublicKey, String? deviceName, + String? contactUri, }) async { if (pings.isEmpty) { debugLog('[OFFLINE] No pings to save, skipping session creation'); @@ -167,6 +173,7 @@ class OfflineSessionService { data: sessionData, devicePublicKey: devicePublicKey, deviceName: deviceName, + contactUri: contactUri, ); _sessions.insert(0, session); // Add at beginning (newest first) From ae7fb0300e222a05ad6bfc24bd03a78a2cb4f3a8 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Wed, 11 Mar 2026 23:01:08 -0400 Subject: [PATCH 28/57] Add heartbeat retry, local session expiry tracking, and offline queue preservation - Heartbeat retries on network failure with exponential backoff (5 attempts, 30s-120s) - Local session deadline timer fires at expires_at, triggers session error if backend is unreachable - On session expiry, queued wardrive data is saved as an offline session instead of discarded --- lib/providers/app_state_provider.dart | 23 ++++++++ lib/services/api_queue_service.dart | 18 ++++++ lib/services/api_service.dart | 84 +++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index a7d50bf..d859ecb 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -3410,6 +3410,29 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { authErrors.contains(reason) || zoneErrors.contains(reason)) { debugLog('[API] Session error requires disconnect: $reason'); + + // Preserve queued wardrive data to offline storage before disconnect clears it + if (sessionErrors.contains(reason)) { + try { + final queuedPings = await _apiQueueService.extractAllAsJson(); + if (queuedPings.isNotEmpty) { + final offlineDeviceName = _isAnonymousRenamed + ? _originalDeviceName + : (_meshCoreConnection?.selfInfo?.name ?? + connectedDeviceName?.replaceFirst('MeshCore-', '')); + await _offlineSessionService.saveSession( + queuedPings, + devicePublicKey: _devicePublicKey, + deviceName: offlineDeviceName, + contactUri: _offlineContactUri, + ); + debugLog('[APP] Preserved ${queuedPings.length} queued pings to offline storage on session expiry'); + } + } catch (e) { + debugError('[APP] Failed to preserve queue to offline storage: $e'); + } + } + // Don't call requestAuth disconnect - session is already invalid on server // Just cleanup locally and disconnect await disconnect(); diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index 17b598f..b03ab9f 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -636,6 +636,24 @@ class ApiQueueService { _offlinePings.clear(); } + /// Extract all queued items as API JSON without clearing the queue. + /// Used to preserve data before session-expiry disconnect. + Future>> extractAllAsJson() async { + // Flush RX buffer first so all items are in the main queue + await _flushRxBuffer(); + + final hiveItems = _safeRead( + (box) => box.values.toList(), + [], + ); + + final allItems = [...hiveItems, ..._memoryQueue]; + + if (allItems.isEmpty) return []; + + return allItems.map((item) => item.toApiJson()).toList(); + } + /// Dispose of resources void dispose() { _batchTimer?.cancel(); diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 72d8300..aed7fb7 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:math'; import 'package:http/http.dart' as http; @@ -38,6 +39,10 @@ class ApiService { bool _rxAllowed = false; int? _sessionExpiresAt; Timer? _heartbeatTimer; + Timer? _heartbeatRetryTimer; + Timer? _sessionDeadlineTimer; + int _heartbeatRetryCount = 0; + static const int _maxHeartbeatRetries = 5; Function? _onSessionExpiring; List _channels = []; List _scopes = []; @@ -590,6 +595,11 @@ class ApiService { _gpsProvider = null; _heartbeatTimer?.cancel(); _heartbeatTimer = null; + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = null; + _heartbeatRetryCount = 0; + _sessionDeadlineTimer?.cancel(); + _sessionDeadlineTimer = null; debugLog('[HEARTBEAT] Heartbeat mode disabled'); } @@ -597,9 +607,12 @@ class ApiService { /// Matches scheduleHeartbeat() in wardrive.js /// @param expiresAt Unix timestamp when session expires void scheduleHeartbeat(int expiresAt) { - // Cancel any existing heartbeat timer + // Cancel any existing heartbeat timer and reset retry state _heartbeatTimer?.cancel(); _heartbeatTimer = null; + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = null; + _heartbeatRetryCount = 0; if (!_heartbeatEnabled) return; @@ -612,15 +625,17 @@ class ApiService { // Session is about to expire or already expired - send heartbeat immediately debugWarn('[HEARTBEAT] Session expires in ${secondsUntilExpiry}s, sending immediately'); _sendScheduledHeartbeat(); - return; - } + } else { + debugLog('[HEARTBEAT] Scheduling in ${secondsUntilHeartbeat}s (session expires in ${secondsUntilExpiry}s)'); - debugLog('[HEARTBEAT] Scheduling in ${secondsUntilHeartbeat}s (session expires in ${secondsUntilExpiry}s)'); + _heartbeatTimer = Timer(Duration(seconds: secondsUntilHeartbeat), () { + debugLog('[HEARTBEAT] Timer fired, sending keepalive'); + _sendScheduledHeartbeat(); + }); + } - _heartbeatTimer = Timer(Duration(seconds: secondsUntilHeartbeat), () { - debugLog('[HEARTBEAT] Timer fired, sending keepalive'); - _sendScheduledHeartbeat(); - }); + // Schedule session deadline timer at exact expiry + _scheduleSessionDeadline(expiresAt); } /// Send scheduled heartbeat with GPS coordinates @@ -631,10 +646,22 @@ class ApiService { if (result?['success'] == true) { debugLog('[HEARTBEAT] Heartbeat successful'); + // Reset retry state on success + _heartbeatRetryCount = 0; + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = null; // Next heartbeat will be scheduled when we get new expires_at } else if (result == null) { - // Network error — transient, trigger session expiring - debugWarn('[HEARTBEAT] Heartbeat failed: network error'); + // Network error — schedule retry with exponential backoff + if (_heartbeatRetryCount < _maxHeartbeatRetries) { + final delay = min(30 * pow(2, _heartbeatRetryCount).toInt(), 120); + _heartbeatRetryCount++; + debugWarn('[HEARTBEAT] Network error, scheduling retry $_heartbeatRetryCount/$_maxHeartbeatRetries in ${delay}s'); + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = Timer(Duration(seconds: delay), _sendScheduledHeartbeat); + } else { + debugError('[HEARTBEAT] Network error, all $_maxHeartbeatRetries retries exhausted'); + } _onSessionExpiring?.call(); } else { // Server returned an error — check if critical @@ -657,7 +684,33 @@ class ApiService { } } - /// Clear session data and cancel heartbeat timer + /// Schedule a hard deadline timer at the exact session expiry time. + /// If the server is unreachable and all heartbeat retries fail, this fires + /// and triggers the same disconnect flow as a server-returned session_expired. + void _scheduleSessionDeadline(int expiresAt) { + _sessionDeadlineTimer?.cancel(); + if (!_heartbeatEnabled) return; + + final now = DateTime.now().millisecondsSinceEpoch ~/ 1000; + final secondsUntilExpiry = expiresAt - now; + + if (secondsUntilExpiry <= 0) { + _onSessionDeadlineReached(); + return; + } + + debugLog('[HEARTBEAT] Session deadline set for ${secondsUntilExpiry}s from now'); + _sessionDeadlineTimer = Timer(Duration(seconds: secondsUntilExpiry), _onSessionDeadlineReached); + } + + /// Called when the session deadline timer fires — server was unreachable + void _onSessionDeadlineReached() { + debugError('[HEARTBEAT] Session deadline reached - server unreachable, triggering session expiry'); + _clearSession(); + onSessionError?.call('session_expired', 'Session has timed out (server unreachable)'); + } + + /// Clear session data and cancel all timers void _clearSession() { _sessionId = null; _txAllowed = false; @@ -671,6 +724,11 @@ class ApiService { _apiHopBytes = 1; _heartbeatTimer?.cancel(); _heartbeatTimer = null; + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = null; + _heartbeatRetryCount = 0; + _sessionDeadlineTimer?.cancel(); + _sessionDeadlineTimer = null; debugLog('[API] Session cleared'); } @@ -807,6 +865,10 @@ class ApiService { void dispose() { _heartbeatTimer?.cancel(); _heartbeatTimer = null; + _heartbeatRetryTimer?.cancel(); + _heartbeatRetryTimer = null; + _sessionDeadlineTimer?.cancel(); + _sessionDeadlineTimer = null; _client.close(); } } From 40b3da910c32f4466af14c88321935e836ef20b6 Mon Sep 17 00:00:00 2001 From: Rob Ekl Date: Sat, 14 Mar 2026 20:19:34 -0500 Subject: [PATCH 29/57] Cancel stale auto-ping restore timers (#10) LGTM. Right fix, matches the pattern used by _reconnectTimer and _reconnectTimeoutTimer. The generation counter is slightly defensive given Dart's single-threaded model but adds no complexity so no complaints. --- lib/providers/app_state_provider.dart | 29 +++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index d859ecb..81a3b3c 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -225,8 +225,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { int _reconnectAttempt = 0; Timer? _reconnectTimer; Timer? _reconnectTimeoutTimer; + Timer? _restoreAutoPingTimer; bool _autoPingWasEnabled = false; AutoMode _autoModeBeforeReconnect = AutoMode.active; + int _reconnectRestoreGeneration = 0; static const int _maxReconnectAttempts = 3; static const Duration _reconnectDelay = Duration(seconds: 3); @@ -1916,6 +1918,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } Future _fullDisconnectCleanup() async { + _cancelPendingAutoPingRestore(); _connectionStep = ConnectionStep.disconnected; // Stop heartbeat immediately on BLE disconnect @@ -1977,6 +1980,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { /// Start auto-reconnect after unexpected BLE disconnect Future _startAutoReconnect() async { + _cancelPendingAutoPingRestore(); _isAutoReconnecting = true; _reconnectAttempt = 0; _connectionStep = ConnectionStep.reconnecting; @@ -2098,9 +2102,21 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Restore auto-ping if it was active if (wasAutoPing) { + final restoreGeneration = _reconnectRestoreGeneration; // Use a short delay to ensure connection is fully set up - Timer(const Duration(milliseconds: 500), () { - if (_connectionStep == ConnectionStep.connected) { + _restoreAutoPingTimer?.cancel(); + _restoreAutoPingTimer = Timer(const Duration(milliseconds: 500), () { + _restoreAutoPingTimer = null; + if (_isDisposed || + restoreGeneration != _reconnectRestoreGeneration || + _userRequestedDisconnect || + _connectionStep != ConnectionStep.connected || + _pingService == null) { + debugLog('[CONN] Skipping delayed auto-ping restore (stale or disconnected state)'); + return; + } + + if (!_autoPingEnabled) { toggleAutoPing(previousMode); debugLog('[CONN] Auto-ping restored after reconnect (mode=$previousMode)'); } @@ -2123,6 +2139,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _reconnectTimer = null; _reconnectTimeoutTimer?.cancel(); _reconnectTimeoutTimer = null; + _cancelPendingAutoPingRestore(); // Clear reconnect state _isAutoReconnecting = false; @@ -2153,6 +2170,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _reconnectTimer = null; _reconnectTimeoutTimer?.cancel(); _reconnectTimeoutTimer = null; + _cancelPendingAutoPingRestore(); _isAutoReconnecting = false; _reconnectAttempt = 0; _autoPingWasEnabled = false; @@ -4494,6 +4512,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Cleanup // ============================================ + void _cancelPendingAutoPingRestore() { + _restoreAutoPingTimer?.cancel(); + _restoreAutoPingTimer = null; + _reconnectRestoreGeneration++; + } + @override @override void notifyListeners() { @@ -4516,6 +4540,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _zoneCheckCountdownTimer?.cancel(); _reconnectTimer?.cancel(); _reconnectTimeoutTimer?.cancel(); + _restoreAutoPingTimer?.cancel(); _tileRefreshTimer?.cancel(); _unifiedRxHandler?.dispose(); _meshCoreConnection?.dispose(); From 8d53b49401acaf849eb4dbcccb66237f4954b787 Mon Sep 17 00:00:00 2001 From: Rob Ekl Date: Sat, 14 Mar 2026 20:20:19 -0500 Subject: [PATCH 30/57] Recheck location permission after disclosure (#11) Clean separation of disclosure (show once) from permission (always recheck), plus proper permanently-denied handling --- lib/screens/main_scaffold.dart | 54 +++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/screens/main_scaffold.dart b/lib/screens/main_scaffold.dart index cd28c2c..87c2c43 100644 --- a/lib/screens/main_scaffold.dart +++ b/lib/screens/main_scaffold.dart @@ -26,6 +26,7 @@ class MainScaffold extends StatefulWidget { class _MainScaffoldState extends State { int _selectedIndex = 0; bool _hasCheckedDisclosure = false; + bool _hasShownLocationSettingsPrompt = false; final List _screens = [ const HomeScreen(), @@ -59,18 +60,15 @@ class _MainScaffoldState extends State { // Check if disclosure was already shown final hasShown = await PermissionDisclosureService.hasShownDisclosure(); - if (hasShown) { - debugLog('[DISCLOSURE] Already shown, skipping'); - return; + if (!hasShown) { + // Show the disclosure dialog + if (!mounted) return; + debugLog('[DISCLOSURE] Showing location disclosure dialog'); + await PermissionDisclosureService.showLocationDisclosure(context); } - // Show the disclosure dialog - if (!mounted) return; - debugLog('[DISCLOSURE] Showing location disclosure dialog'); - await PermissionDisclosureService.showLocationDisclosure(context); - - debugLog('[DISCLOSURE] User acknowledged, requesting permissions'); - await _requestPermissionsAfterDisclosure(); + debugLog('[DISCLOSURE] Ensuring location permission after disclosure'); + await _ensureLocationPermission(); } /// Request GPS permission on web (triggers browser's native prompt) @@ -93,8 +91,10 @@ class _MainScaffoldState extends State { } } - /// Request permissions after user accepts disclosure - Future _requestPermissionsAfterDisclosure() async { + /// Ensure location permission after disclosure has been shown. + /// Requests when possible, restarts GPS when granted, and surfaces a settings CTA + /// when the permission has been permanently denied. + Future _ensureLocationPermission() async { bool granted = false; if (Platform.isIOS) { @@ -104,12 +104,23 @@ class _MainScaffoldState extends State { permission = await Geolocator.requestPermission(); } debugLog('[DISCLOSURE] iOS location permission: $permission'); + if (permission == LocationPermission.deniedForever) { + _showLocationSettingsPrompt(); + return; + } granted = permission == LocationPermission.always || permission == LocationPermission.whileInUse; } else { - // Android: Request location via permission_handler - final status = await Permission.locationWhenInUse.request(); + // Android: only request if needed so previously granted permission just restarts GPS. + var status = await Permission.locationWhenInUse.status; + if (status.isDenied) { + status = await Permission.locationWhenInUse.request(); + } debugLog('[DISCLOSURE] Android location permission: $status'); + if (status.isPermanentlyDenied) { + _showLocationSettingsPrompt(); + return; + } granted = status.isGranted; } @@ -121,6 +132,21 @@ class _MainScaffoldState extends State { } } + void _showLocationSettingsPrompt() { + if (!mounted || _hasShownLocationSettingsPrompt) return; + _hasShownLocationSettingsPrompt = true; + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Location permission is disabled in system settings.'), + action: SnackBarAction( + label: 'Settings', + onPressed: Geolocator.openAppSettings, + ), + ), + ); + } + @override Widget build(BuildContext context) { final appState = context.watch(); From bfb9a85233fdc667a35f7c98ef4fd4b99f442691 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 21:44:01 -0400 Subject: [PATCH 31/57] - Discovery pings now extract repeater IDs using the region's hop byte count instead of always assuming 1 byte. In multi-byte regions, TX/RX logs showed full IDs like "4E7A" while discovery logs still showed the truncated "4E" --- lib/models/log_entry.dart | 2 +- lib/providers/app_state_provider.dart | 7 ++----- lib/screens/settings_screen.dart | 20 ++++++++++---------- lib/services/meshcore/disc_tracker.dart | 11 +++++++---- lib/services/meshcore/packet_validator.dart | 12 ++++++++++++ lib/services/meshcore/rx_logger.dart | 2 +- lib/services/meshcore/tx_tracker.dart | 2 +- lib/services/ping_service.dart | 8 +++++++- 8 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/models/log_entry.dart b/lib/models/log_entry.dart index 399da9b..b4b81a0 100644 --- a/lib/models/log_entry.dart +++ b/lib/models/log_entry.dart @@ -201,7 +201,7 @@ class DiscLogEntry { /// Discovered node entry for log display class DiscoveredNodeEntry { - final String repeaterId; // First 2 hex chars of pubkey (e.g., "77", "4E") + final String repeaterId; // First N hex chars of pubkey based on hopBytes (e.g., "4E", "4E7A", "4E7A3B") final String nodeType; // "REPEATER" or "ROOM" final double localSnr; // SNR as seen by local device (dB) final int localRssi; // RSSI as seen by local device (dBm) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 81a3b3c..c295f04 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1168,14 +1168,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { txTracker: _txTracker, audioService: _audioService, disableRssiFilter: _preferences.disableRssiFilter, + hopBytes: effectiveHopBytes, shouldIgnoreRepeater: (String repeaterId) { - // Same filter as RxLogger - check user preferences for ignored repeater ID - // Uses startsWith() for prefix matching across different hop byte sizes final prefs = _preferences; if (prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null) { - final ignored = prefs.ignoreRepeaterId!.toUpperCase(); - final current = repeaterId.toUpperCase(); - return current.startsWith(ignored) || ignored.startsWith(current); + return PacketValidator.isCarpeaterIdMatch(repeaterId, prefs.ignoreRepeaterId!); } return false; }, diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 77e6378..7e00f46 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1201,9 +1201,8 @@ class _SettingsScreenState extends State { } void _showRepeaterIdDialog(BuildContext context, AppStateProvider appState) { - final effectiveBytes = appState.effectiveHopBytes; - final maxHexChars = effectiveBytes * 2; - final hintText = 'F' * maxHexChars; + const maxHexChars = 6; + const hintText = 'FFFFFF'; final controller = TextEditingController( text: appState.preferences.ignoreRepeaterId ?? '', @@ -1217,15 +1216,15 @@ class _SettingsScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Enter the repeater ID of your CARpeater ($maxHexChars hex digits):'), + const Text('Enter the full 3-byte repeater ID (6 hex digits):'), const SizedBox(height: 16), TextField( controller: controller, - decoration: InputDecoration( + decoration: const InputDecoration( labelText: 'CARpeater ID', hintText: hintText, prefixText: '0x', - border: const OutlineInputBorder(), + border: OutlineInputBorder(), ), maxLength: maxHexChars, textCapitalization: TextCapitalization.characters, @@ -1242,7 +1241,9 @@ class _SettingsScreenState extends State { ), const SizedBox(height: 8), Text( - 'Multi-hop packets through your CARpeater will be stripped to report the underlying repeater with null signal data. Single-hop CARpeater packets are still dropped.', + 'Enter all 6 hex digits of your CARpeater\'s ID. ' + 'The app will automatically truncate to match your region\'s hop byte size (1, 2, or 3 bytes). ' + 'Multi-hop packets through your CARpeater will be stripped to report the underlying repeater.', style: TextStyle( fontSize: 12, color: Colors.grey[600], @@ -1258,9 +1259,8 @@ class _SettingsScreenState extends State { TextButton( onPressed: () { final value = controller.text.trim().toUpperCase(); - // Accept hex IDs of any valid even length (2, 4, or 6 chars) final isValidHex = value.isEmpty || - (value.length % 2 == 0 && value.length <= 6 && + (value.length == maxHexChars && RegExp(r'^[0-9A-F]+$').hasMatch(value)); if (isValidHex) { @@ -1274,7 +1274,7 @@ class _SettingsScreenState extends State { ); Navigator.pop(context); } else { - AppToast.warning(context, 'Invalid hex value. Use $maxHexChars hex digits.'); + AppToast.warning(context, 'Please enter exactly 6 hex digits (3-byte ID).'); } }, child: const Text('Save'), diff --git a/lib/services/meshcore/disc_tracker.dart b/lib/services/meshcore/disc_tracker.dart index 3013013..5796d6f 100644 --- a/lib/services/meshcore/disc_tracker.dart +++ b/lib/services/meshcore/disc_tracker.dart @@ -31,7 +31,10 @@ class DiscTracker { /// Parameters: (node, isNew) - isNew is true for first time seeing this node void Function(DiscoveredNode node, bool isNew)? onNodeDiscovered; - DiscTracker({this.shouldIgnoreRepeater, this.disableRssiFilter = false}); + /// Number of bytes per hop in path hash (1, 2, or 3). Controls repeater ID length. + final int hopBytes; + + DiscTracker({this.shouldIgnoreRepeater, this.disableRssiFilter = false, this.hopBytes = 1}); /// Callback fired when discovery window completes void Function(List discoveredNodes)? onWindowComplete; @@ -134,8 +137,8 @@ class DiscTracker { final pubkey = rawBytes.sublist(7, 39); final pubkeyHex = pubkey.map((b) => b.toRadixString(16).padLeft(2, '0')).join('').toUpperCase(); - // Get repeater ID (first 2 hex chars = first byte) - final repeaterId = pubkeyHex.substring(0, 2); + // Get repeater ID (first N hex chars based on hopBytes setting) + final repeaterId = pubkeyHex.substring(0, hopBytes * 2); // Check if this repeater should be ignored (user carpeater filter) if (shouldIgnoreRepeater != null && shouldIgnoreRepeater!(repeaterId)) { @@ -209,7 +212,7 @@ class DiscTracker { /// Discovered node data class DiscoveredNode { - final String repeaterId; // First 2 hex chars of pubkey (e.g., "77", "4E") + final String repeaterId; // First N hex chars of pubkey based on hopBytes (e.g., "4E", "4E7A", "4E7A3B") final int nodeType; // 0x01 = REPEATER, 0x02 = ROOM final double localSnr; // SNR as seen by local device (dB) final int localRssi; // RSSI as seen by local device (dBm) diff --git a/lib/services/meshcore/packet_validator.dart b/lib/services/meshcore/packet_validator.dart index 8cfd5d0..e9cec94 100644 --- a/lib/services/meshcore/packet_validator.dart +++ b/lib/services/meshcore/packet_validator.dart @@ -172,6 +172,18 @@ class PacketValidator { return rssi >= maxRssiThreshold; } + /// Check if a hop hex string matches a stored CARpeater ID using prefix truncation. + /// The stored ID is always 3-byte (6 hex chars). Incoming hop IDs vary by the + /// packet's path hash size (1, 2, or 3 bytes). Compares the shorter prefix. + /// Also handles legacy shorter stored IDs from before the 3-byte requirement. + static bool isCarpeaterIdMatch(String hopHex, String storedId) { + final hop = hopHex.toUpperCase(); + final stored = storedId.toUpperCase(); + final compareLen = hop.length < stored.length ? hop.length : stored.length; + if (compareLen == 0) return false; + return hop.substring(0, compareLen) == stored.substring(0, compareLen); + } + /// Calculate ratio of printable ASCII characters (32-126) static double getPrintableRatio(String text) { if (text.isEmpty) return 0.0; diff --git a/lib/services/meshcore/rx_logger.dart b/lib/services/meshcore/rx_logger.dart index 9c464b3..0451fff 100644 --- a/lib/services/meshcore/rx_logger.dart +++ b/lib/services/meshcore/rx_logger.dart @@ -88,7 +88,7 @@ class RxLogger { // CARpeater check: the carpeater is co-located with us, so it only // appears as the last hop (the delivery repeater) on RX packets - if (carpeaterPrefix != null && lastHopHex == carpeaterPrefix!.toUpperCase()) { + if (carpeaterPrefix != null && PacketValidator.isCarpeaterIdMatch(lastHopHex, carpeaterPrefix!)) { if (metadata.pathHashCount < 2) { debugLog('[RX LOG] CARpeater pass-through: single-hop, dropping'); return false; diff --git a/lib/services/meshcore/tx_tracker.dart b/lib/services/meshcore/tx_tracker.dart index 21e63a4..50b1d2c 100644 --- a/lib/services/meshcore/tx_tracker.dart +++ b/lib/services/meshcore/tx_tracker.dart @@ -125,7 +125,7 @@ class TxTracker { double? reportedSnr = metadata.snr; int? reportedRssi = metadata.rssi; - if (carpeaterPrefix != null && pathHex.toUpperCase() == carpeaterPrefix!.toUpperCase()) { + if (carpeaterPrefix != null && PacketValidator.isCarpeaterIdMatch(pathHex, carpeaterPrefix!)) { if (metadata.pathHashCount < 2) { debugLog('[TX LOG] CARpeater pass-through: single-hop, dropping'); return false; diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 54513f4..cb9f10d 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -61,6 +61,9 @@ class PingService { final AudioService? _audioService; final bool Function(String repeaterId)? shouldIgnoreRepeater; + /// Number of bytes per hop in path hash (1, 2, or 3). Passed to DiscTracker for repeater ID length. + final int _hopBytes; + /// When true, skip RSSI carpeater check in DiscTracker (user setting) bool disableRssiFilter; @@ -166,6 +169,7 @@ class PingService { AudioService? audioService, this.shouldIgnoreRepeater, this.disableRssiFilter = false, + int hopBytes = 1, }) : _gpsService = gpsService, _connection = connection, _apiQueue = apiQueue, @@ -176,7 +180,8 @@ class PingService { _discoveryWindowCountdown = discoveryWindowTimer, _deviceId = deviceId, _txTracker = txTracker, - _audioService = audioService; + _audioService = audioService, + _hopBytes = hopBytes; /// Get current ping statistics PingStats get stats => _stats; @@ -943,6 +948,7 @@ class PingService { final tracker = DiscTracker( shouldIgnoreRepeater: shouldIgnoreRepeater, disableRssiFilter: disableRssiFilter, + hopBytes: _hopBytes, ); _discTracker = tracker; tracker.onCarpeaterDrop = onDiscCarpeaterDrop; From e3d907433334d60e4962c49c2b77a9c6fe1a5f3a Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 21:55:11 -0400 Subject: [PATCH 32/57] fixed overflow in disc request byte count fix --- lib/widgets/map_widget.dart | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 7448452..70abdab 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -1711,6 +1711,21 @@ class _MapWidgetState extends State with TickerProviderStateMixin { ); } + /// Compute node column width based on hop byte count. + /// [extraPadding] adds space for additional content (e.g. nodeTypeLabel in DISC popup). + double _nodeColumnWidth({double extraPadding = 0}) { + final appState = context.read(); + final hopBytes = appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes; + switch (hopBytes) { + case 2: + return 70 + extraPadding; + case 3: + return 80 + extraPadding; + default: + return 60 + extraPadding; + } + } + /// Show TX ping details popup void _showTxPingDetails(TxPing ping) { // Use the heardRepeaters directly from the TxPing @@ -1834,7 +1849,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { child: Row( children: [ SizedBox( - width: 60, + width: _nodeColumnWidth(), child: Text( 'Node', style: TextStyle( @@ -1903,7 +1918,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { child: Row( children: [ // Repeater ID - RepeaterIdChip(repeaterId: repeater.repeaterId, fontSize: 13, width: 60), + RepeaterIdChip(repeaterId: repeater.repeaterId, fontSize: 13, width: _nodeColumnWidth()), // SNR Expanded( child: Center( @@ -2072,7 +2087,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { child: Row( children: [ SizedBox( - width: 60, + width: _nodeColumnWidth(), child: Text( 'Node', style: TextStyle( @@ -2116,7 +2131,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { child: Row( children: [ // Repeater ID - RepeaterIdChip(repeaterId: ping.repeaterId, fontSize: 13, width: 60), + RepeaterIdChip(repeaterId: ping.repeaterId, fontSize: 13, width: _nodeColumnWidth()), // SNR Expanded( child: Center( @@ -2270,7 +2285,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { child: Row( children: [ SizedBox( - width: 60, + width: _nodeColumnWidth(extraPadding: 20), child: Text( 'Node', style: TextStyle( @@ -2355,7 +2370,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { children: [ // Node ID with type SizedBox( - width: 60, + width: _nodeColumnWidth(extraPadding: 20), child: Row( children: [ RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 13), From 35e28e943c074a634e0621dbec6f9f753d8678b9 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 22:03:32 -0400 Subject: [PATCH 33/57] - Added option to keep the #wardriving channel after exiting a session (#149, @Skye) --- lib/models/user_preferences.dart | 12 +++++++++++- lib/providers/app_state_provider.dart | 6 +++++- lib/screens/settings_screen.dart | 11 +++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index a653799..483d221 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -73,6 +73,9 @@ class UserPreferences { /// Discovery drop: count failed discoveries as failed pings and report to API final bool discDropEnabled; + /// Delete wardriving channel from radio on disconnect + final bool deleteChannelOnDisconnect; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -98,6 +101,7 @@ class UserPreferences { this.disableRssiFilter = false, this.anonymousMode = false, this.discDropEnabled = false, + this.deleteChannelOnDisconnect = true, }); /// Create from JSON (for persistence) @@ -127,6 +131,7 @@ class UserPreferences { disableRssiFilter: (json['disableRssiFilter'] as bool?) ?? false, anonymousMode: (json['anonymousMode'] as bool?) ?? false, discDropEnabled: (json['discDropEnabled'] as bool?) ?? false, + deleteChannelOnDisconnect: (json['deleteChannelOnDisconnect'] as bool?) ?? true, ); } @@ -157,6 +162,7 @@ class UserPreferences { 'disableRssiFilter': disableRssiFilter, 'anonymousMode': anonymousMode, 'discDropEnabled': discDropEnabled, + 'deleteChannelOnDisconnect': deleteChannelOnDisconnect, }; } @@ -186,6 +192,7 @@ class UserPreferences { bool? disableRssiFilter, bool? anonymousMode, bool? discDropEnabled, + bool? deleteChannelOnDisconnect, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -212,6 +219,7 @@ class UserPreferences { disableRssiFilter: disableRssiFilter ?? this.disableRssiFilter, anonymousMode: anonymousMode ?? this.anonymousMode, discDropEnabled: discDropEnabled ?? this.discDropEnabled, + deleteChannelOnDisconnect: deleteChannelOnDisconnect ?? this.deleteChannelOnDisconnect, ); } @@ -263,7 +271,8 @@ class UserPreferences { other.mapRotationLocked == mapRotationLocked && other.disableRssiFilter == disableRssiFilter && other.anonymousMode == anonymousMode && - other.discDropEnabled == discDropEnabled; + other.discDropEnabled == discDropEnabled && + other.deleteChannelOnDisconnect == deleteChannelOnDisconnect; } @override @@ -292,6 +301,7 @@ class UserPreferences { disableRssiFilter, anonymousMode, discDropEnabled, + deleteChannelOnDisconnect, ]); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index c295f04..f8c8100 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -2240,7 +2240,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Delete wardriving channel FIRST, while BLE connection is still active // This prevents "GATT Server is disconnected" errors - await _meshCoreConnection?.deleteWardrivingChannelEarly(); + if (_preferences.deleteChannelOnDisconnect) { + await _meshCoreConnection?.deleteWardrivingChannelEarly(); + } else { + debugLog('[CHANNEL] Skipping channel deletion (user preference)'); + } // Cleanup unified RX handler and TX tracker _logRxDataSubscription?.cancel(); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 7e00f46..bedbb20 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -257,6 +257,17 @@ class _SettingsScreenState extends State { }, ), + // Delete Channel on Disconnect Toggle + SwitchListTile( + secondary: const Icon(Icons.delete_sweep), + title: const Text('Delete Channel on Disconnect'), + subtitle: const Text('Remove #wardriving channel from radio when disconnecting'), + value: prefs.deleteChannelOnDisconnect, + onChanged: (value) { + appState.updatePreferences(prefs.copyWith(deleteChannelOnDisconnect: value)); + }, + ), + // Disable RSSI Filter Toggle SwitchListTile( secondary: const Icon(Icons.shield_outlined), From 2645d73941bc9ddd71ed570657d24ac0e3277075 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 22:14:29 -0400 Subject: [PATCH 34/57] - Minimum ping distance is now configurable for TX and discovery pings. The default 25m floor stays the same, but users can increase it to reduce unnecessary pings in dense city driving or stop-and-go traffic. RX batch flushing distance is unaffected. --- lib/models/user_preferences.dart | 22 +++++++++- lib/providers/app_state_provider.dart | 8 ++++ lib/screens/settings_screen.dart | 59 +++++++++++++++++++++++++++ lib/services/gps_service.dart | 16 +++++++- lib/services/ping_service.dart | 9 ++-- 5 files changed, 108 insertions(+), 6 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index 483d221..706c440 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -76,6 +76,9 @@ class UserPreferences { /// Delete wardriving channel from radio on disconnect final bool deleteChannelOnDisconnect; + /// Minimum ping distance in meters (25m floor, user can increase) + final int minPingDistanceMeters; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -102,6 +105,7 @@ class UserPreferences { this.anonymousMode = false, this.discDropEnabled = false, this.deleteChannelOnDisconnect = true, + this.minPingDistanceMeters = 25, }); /// Create from JSON (for persistence) @@ -132,6 +136,7 @@ class UserPreferences { anonymousMode: (json['anonymousMode'] as bool?) ?? false, discDropEnabled: (json['discDropEnabled'] as bool?) ?? false, deleteChannelOnDisconnect: (json['deleteChannelOnDisconnect'] as bool?) ?? true, + minPingDistanceMeters: (json['minPingDistanceMeters'] as int?) ?? 25, ); } @@ -163,6 +168,7 @@ class UserPreferences { 'anonymousMode': anonymousMode, 'discDropEnabled': discDropEnabled, 'deleteChannelOnDisconnect': deleteChannelOnDisconnect, + 'minPingDistanceMeters': minPingDistanceMeters, }; } @@ -193,6 +199,7 @@ class UserPreferences { bool? anonymousMode, bool? discDropEnabled, bool? deleteChannelOnDisconnect, + int? minPingDistanceMeters, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -220,6 +227,7 @@ class UserPreferences { anonymousMode: anonymousMode ?? this.anonymousMode, discDropEnabled: discDropEnabled ?? this.discDropEnabled, deleteChannelOnDisconnect: deleteChannelOnDisconnect ?? this.deleteChannelOnDisconnect, + minPingDistanceMeters: minPingDistanceMeters ?? this.minPingDistanceMeters, ); } @@ -245,6 +253,9 @@ class UserPreferences { return '$autoPingInterval seconds'; } + /// Get min ping distance display string + String get minPingDistanceDisplay => '${minPingDistanceMeters}m'; + @override bool operator ==(Object other) { if (identical(this, other)) return true; @@ -272,7 +283,8 @@ class UserPreferences { other.disableRssiFilter == disableRssiFilter && other.anonymousMode == anonymousMode && other.discDropEnabled == discDropEnabled && - other.deleteChannelOnDisconnect == deleteChannelOnDisconnect; + other.deleteChannelOnDisconnect == deleteChannelOnDisconnect && + other.minPingDistanceMeters == minPingDistanceMeters; } @override @@ -302,6 +314,7 @@ class UserPreferences { anonymousMode, discDropEnabled, deleteChannelOnDisconnect, + minPingDistanceMeters, ]); } @@ -336,3 +349,10 @@ class AutoPingInterval { static const List values = [fast, normal, slow]; } + +/// Minimum ping distance options (meters) +class MinPingDistance { + static const int min = 25; + + static const List values = [25, 50, 75, 150]; +} diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index f8c8100..72ec57d 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -3182,6 +3182,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Propagate CARpeater prefix to live trackers _syncCarpeaterPrefix(); + // Propagate min ping distance to GpsService and PingService + _gpsService.setMinPingDistance(preferences.minPingDistanceMeters.toDouble()); + PingService.currentMinDistance = preferences.minPingDistanceMeters; + notifyListeners(); _savePreferences(); } @@ -4198,6 +4202,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Loaded preferences: interval=${_preferences.autoPingInterval}s, ' 'ignoreCarpeater=${_preferences.ignoreCarpeater}, ' 'ignoreRepeaterId=${_preferences.ignoreRepeaterId}'); + + // Apply saved min ping distance to GpsService and PingService + _gpsService.setMinPingDistance(_preferences.minPingDistanceMeters.toDouble()); + PingService.currentMinDistance = _preferences.minPingDistanceMeters; } } catch (e) { debugLog('[APP] Failed to load preferences: $e'); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index bedbb20..314af8c 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -147,6 +147,16 @@ class _SettingsScreenState extends State { onTap: isAutoMode ? null : () => _showIntervalSelector(context, appState), ), + // Min Ping Distance Selector + ListTile( + leading: const Icon(Icons.straighten), + title: const Text('Min Ping Distance'), + subtitle: Text(prefs.minPingDistanceDisplay), + trailing: const Icon(Icons.chevron_right), + enabled: !isAutoMode, + onTap: isAutoMode ? null : () => _showDistanceSelector(context, appState), + ), + // Hybrid Mode Toggle SwitchListTile( secondary: const Icon(Icons.compare_arrows), @@ -1211,6 +1221,55 @@ class _SettingsScreenState extends State { ); } + void _showDistanceSelector(BuildContext context, AppStateProvider appState) { + final currentDistance = appState.preferences.minPingDistanceMeters; + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Select Min Ping Distance'), + content: RadioGroup( + groupValue: currentDistance, + onChanged: (value) { + if (value != null) { + appState.updatePreferences( + appState.preferences.copyWith(minPingDistanceMeters: value), + ); + Navigator.pop(context); + } + }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: MinPingDistance.values.map((distance) { + String description; + if (distance == 25) { + description = 'Default'; + } else if (distance == 50) { + description = 'City driving'; + } else if (distance == 75) { + description = 'Highway'; + } else { + description = 'Long range'; + } + + return RadioListTile( + title: Text('${distance}m'), + subtitle: Text(description), + value: distance, + ); + }).toList(), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + ], + ), + ); + } + void _showRepeaterIdDialog(BuildContext context, AppStateProvider appState) { const maxHexChars = 6; const hintText = 'FFFFFF'; diff --git a/lib/services/gps_service.dart b/lib/services/gps_service.dart index a6c7084..753c67c 100644 --- a/lib/services/gps_service.dart +++ b/lib/services/gps_service.dart @@ -28,6 +28,18 @@ class GpsService { /// Reference: getValidGpsForZoneCheck() in wardrive.js static const double maxAccuracyMetersForZoneCheck = 50.0; + /// Configured minimum ping distance (user-adjustable, clamped to minDistanceMeters floor) + double _configuredMinDistance = minDistanceMeters; + + /// Get the configured minimum ping distance + double get configuredMinDistance => _configuredMinDistance; + + /// Set the minimum ping distance (clamped to 25m floor) + void setMinPingDistance(double meters) { + _configuredMinDistance = meters < minDistanceMeters ? minDistanceMeters : meters; + debugLog('[GPS] Min ping distance set to ${_configuredMinDistance.toInt()}m'); + } + final _statusController = StreamController.broadcast(); final _positionController = StreamController.broadcast(); @@ -274,10 +286,10 @@ class GpsService { ); } - /// Check if current position is far enough from last ping (25m minimum) + /// Check if current position is far enough from last ping bool canPingAtPosition(Position position) { if (_lastPingPosition == null) return true; - return distanceFromLastPing(position) >= minDistanceMeters; + return distanceFromLastPing(position) >= _configuredMinDistance; } /// Mark current position as ping location diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index cb9f10d..cee2547 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -48,6 +48,9 @@ class PingService { /// Cooldown period between manual pings (15 seconds) static const Duration _manualPingCooldown = Duration(seconds: 15); + /// Current configured min ping distance (for validation messages) + static int currentMinDistance = 25; + final GpsService _gpsService; final MeshCoreConnection _connection; final ApiQueueService _apiQueue; @@ -1029,8 +1032,8 @@ class PingService { position.latitude, position.longitude, ); - if (distance < GpsService.minDistanceMeters) { - debugLog('[DISC] Too close to last discovery (${distance.toStringAsFixed(1)}m < 25m), skipping'); + if (distance < _gpsService.configuredMinDistance) { + debugLog('[DISC] Too close to last discovery (${distance.toStringAsFixed(1)}m < ${_gpsService.configuredMinDistance.toInt()}m), skipping'); _skipReason = 'too close'; _pingInProgress = false; _scheduleNextDiscovery(); @@ -1314,7 +1317,7 @@ extension PingValidationExtension on PingValidation { case PingValidation.outsideGeofence: return 'Outside service area'; case PingValidation.tooCloseToLastPing: - return 'Move 25m before next ping'; + return 'Move ${PingService.currentMinDistance}m before next ping'; case PingValidation.cooldownActive: return 'Wait 5 seconds between pings'; case PingValidation.manualCooldownActive: From d451beeb3cbb13a467f4a3d4e1f3591d684a23dd Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 22:21:22 -0400 Subject: [PATCH 35/57] - GPS-related zone check errors (inaccurate/stale) no longer retry every 5 seconds or auto-switch to the error tab. The next zone check waits until the user moves 100m instead of hammering retries while stationary. The zone status bar now shows a GPS icon with "GPS Unavailable" in orange, and the full-screen error view displays a specific title and message with a manual "Retry Zone Check" button. --- lib/providers/app_state_provider.dart | 12 ++++--- lib/screens/connection_screen.dart | 37 ++++++++++++++++++- lib/screens/settings_screen.dart | 52 +++++++++++---------------- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 72ec57d..e675382 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -3702,11 +3702,15 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugError('[GEOFENCE] Zone status check failed: reason=$reason, message=$message'); if (reason == 'gps_inaccurate') { - logError('GPS Accuracy Error\n$message'); - _scheduleZoneCheckRetry(seconds: 5, error: message, reason: 'gps_inaccurate'); + logError('GPS Accuracy Error\n$message', autoSwitch: false); + _zoneCheckError = message; + _zoneCheckErrorReason = 'gps_inaccurate'; + notifyListeners(); } else if (reason == 'gps_stale') { - logError('GPS Stale Error\n$message'); - _scheduleZoneCheckRetry(seconds: 5, error: message, reason: 'gps_stale'); + logError('GPS Stale Error\n$message', autoSwitch: false); + _zoneCheckError = message; + _zoneCheckErrorReason = 'gps_stale'; + notifyListeners(); } else if (reason == 'zone_disabled') { final errorMsg = _getErrorMessage(reason, message); logError(errorMsg); diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index bfa16f9..2610f90 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -998,6 +998,12 @@ class _ConnectionScreenState extends State with WidgetsBinding locationIcon = Icons.wifi_off; locationText = 'No Internet'; locationColor = Colors.red; + // GPS error: show GPS issue indicator + } else if (appState.zoneCheckErrorReason == 'gps_inaccurate' || + appState.zoneCheckErrorReason == 'gps_stale') { + locationIcon = Icons.gps_off; + locationText = 'GPS Unavailable'; + locationColor = Colors.orange; // Show "Checking Zone..." whenever a zone check is in progress // This provides consistent UI feedback during both initial and re-checks } else if (appState.isCheckingZone) { @@ -1393,7 +1399,36 @@ class _ConnectionScreenState extends State with WidgetsBinding ); } - // Non-network errors — show simple error with countdown + // GPS errors — no auto-retry, show manual retry button + if (appState.zoneCheckErrorReason == 'gps_inaccurate' || + appState.zoneCheckErrorReason == 'gps_stale') { + return Column( + children: [ + _buildZoneStatusBar(context, appState), + Expanded( + child: _buildMessageContent( + context: context, + icon: Icons.gps_off, + iconColor: Colors.orange.withValues(alpha: 0.7), + title: appState.zoneCheckErrorReason == 'gps_inaccurate' + ? 'GPS Accuracy Error' + : 'GPS Stale Error', + message: '${appState.zoneCheckError}\n\nTry moving to an area with better GPS signal, then tap retry.', + action: FilledButton.icon( + onPressed: () => appState.checkZoneStatus(), + icon: const Icon(Icons.refresh), + label: const Text('Retry Zone Check'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + ), + ), + ), + ), + ], + ); + } + + // Other non-network errors — show simple error with countdown return Column( children: [ _buildZoneStatusBar(context, appState), diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 314af8c..85de123 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1223,41 +1223,19 @@ class _SettingsScreenState extends State { void _showDistanceSelector(BuildContext context, AppStateProvider appState) { final currentDistance = appState.preferences.minPingDistanceMeters; + final controller = TextEditingController(text: currentDistance.toString()); showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Select Min Ping Distance'), - content: RadioGroup( - groupValue: currentDistance, - onChanged: (value) { - if (value != null) { - appState.updatePreferences( - appState.preferences.copyWith(minPingDistanceMeters: value), - ); - Navigator.pop(context); - } - }, - child: Column( - mainAxisSize: MainAxisSize.min, - children: MinPingDistance.values.map((distance) { - String description; - if (distance == 25) { - description = 'Default'; - } else if (distance == 50) { - description = 'City driving'; - } else if (distance == 75) { - description = 'Highway'; - } else { - description = 'Long range'; - } - - return RadioListTile( - title: Text('${distance}m'), - subtitle: Text(description), - value: distance, - ); - }).toList(), + title: const Text('Min Ping Distance'), + content: TextField( + controller: controller, + keyboardType: TextInputType.number, + autofocus: true, + decoration: const InputDecoration( + suffixText: 'meters', + helperText: 'Minimum ${MinPingDistance.min}m', ), ), actions: [ @@ -1265,6 +1243,18 @@ class _SettingsScreenState extends State { onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), + FilledButton( + onPressed: () { + final value = int.tryParse(controller.text); + if (value != null && value >= MinPingDistance.min) { + appState.updatePreferences( + appState.preferences.copyWith(minPingDistanceMeters: value), + ); + Navigator.pop(context); + } + }, + child: const Text('Save'), + ), ], ), ); From fb2d4c353a381e4ec9b4490b5217d8e2420378c2 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 22:21:58 -0400 Subject: [PATCH 36/57] =?UTF-8?q?=20=20lib/screens/settings=5Fscreen.dart?= =?UTF-8?q?=20=E2=80=94=20Replaced=20the=20radio=20button=20dialog=20with?= =?UTF-8?q?=20a=20text=20field.=20Users=20type=20any=20number=20they=20wan?= =?UTF-8?q?t=20(minimum=2025m=20enforced).=20The=20field=20shows=20=20=20"?= =?UTF-8?q?meters"=20as=20a=20suffix=20and=20"Minimum=2025m"=20as=20helper?= =?UTF-8?q?=20text.=20Save=20button=20only=20accepts=20valid=20integers=20?= =?UTF-8?q?>=3D=2025.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/user_preferences.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index 706c440..c564020 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -350,9 +350,7 @@ class AutoPingInterval { static const List values = [fast, normal, slow]; } -/// Minimum ping distance options (meters) +/// Minimum ping distance (meters) class MinPingDistance { static const int min = 25; - - static const List values = [25, 50, 75, 150]; } From d2fddb599efb06fa5a35450387e0a0f555c1648c Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sat, 14 Mar 2026 22:24:12 -0400 Subject: [PATCH 37/57] - Hybrid mode now defaults to enabled for new users and existing users who haven't explicitly toggled it off. Saved preferences are preserved. --- lib/models/user_preferences.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index c564020..b37b57a 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -97,7 +97,7 @@ class UserPreferences { this.closeAppAfterDisconnect = false, this.themeMode = 'dark', this.unitSystem = 'metric', - this.hybridModeEnabled = false, + this.hybridModeEnabled = true, this.mapAutoFollow = false, this.mapAlwaysNorth = true, this.mapRotationLocked = false, @@ -128,7 +128,7 @@ class UserPreferences { closeAppAfterDisconnect: (json['closeAppAfterDisconnect'] as bool?) ?? false, themeMode: (json['themeMode'] as String?) ?? 'dark', unitSystem: (json['unitSystem'] as String?) ?? 'metric', - hybridModeEnabled: (json['hybridModeEnabled'] as bool?) ?? false, + hybridModeEnabled: (json['hybridModeEnabled'] as bool?) ?? true, mapAutoFollow: (json['mapAutoFollow'] as bool?) ?? false, mapAlwaysNorth: (json['mapAlwaysNorth'] as bool?) ?? true, mapRotationLocked: (json['mapRotationLocked'] as bool?) ?? false, From ee06b4f896484d57792fa3b1f8d25d44dccf39ae Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 13:43:00 -0400 Subject: [PATCH 38/57] Implmented Trace Mode --- lib/models/api_queue_item.dart | 44 ++ lib/models/log_entry.dart | 55 ++ lib/models/noise_floor_session.dart | 11 + lib/models/ping_data.dart | 4 + lib/providers/app_state_provider.dart | 101 ++- lib/screens/connection_screen.dart | 49 ++ lib/screens/home_screen.dart | 18 +- lib/screens/log_screen.dart | 362 +++++++++- lib/screens/settings_screen.dart | 9 + lib/services/api_queue_service.dart | 47 ++ lib/services/background_service.dart | 2 + lib/services/meshcore/connection.dart | 41 ++ lib/services/meshcore/packet_metadata.dart | 6 + lib/services/meshcore/trace_tracker.dart | 212 ++++++ lib/services/meshcore/unified_rx_handler.dart | 19 +- lib/services/ping_service.dart | 285 +++++++- lib/widgets/map_widget.dart | 297 +++++++++ lib/widgets/noise_floor_chart.dart | 7 +- lib/widgets/offline_mode_toggle.dart | 198 ++++++ lib/widgets/ping_controls.dart | 623 ++++++++---------- 20 files changed, 1990 insertions(+), 400 deletions(-) create mode 100644 lib/services/meshcore/trace_tracker.dart create mode 100644 lib/widgets/offline_mode_toggle.dart diff --git a/lib/models/api_queue_item.dart b/lib/models/api_queue_item.dart index 57145e9..337cab1 100644 --- a/lib/models/api_queue_item.dart +++ b/lib/models/api_queue_item.dart @@ -138,6 +138,32 @@ class ApiQueueItem extends HiveObject { ); } + /// Create from a successful TRACE ping (targeted zero-hop trace) + /// heardRepeats format: "repeaterId:localSnr:localRssi:remoteSnr" + factory ApiQueueItem.fromTrace({ + required double latitude, + required double longitude, + required String repeaterId, + required double localSnr, + required int localRssi, + required double remoteSnr, + required int timestamp, + required bool externalAntenna, + int? noiseFloor, + }) { + final heardRepeats = '$repeaterId:${localSnr.toStringAsFixed(2)}:$localRssi:${remoteSnr.toStringAsFixed(2)}'; + return ApiQueueItem( + type: 'TRACE', + latitude: latitude, + longitude: longitude, + timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000), + heardRepeats: heardRepeats, + canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate + externalAntenna: externalAntenna, + noiseFloor: noiseFloor, + ); + } + /// Create from a failed DISC discovery (no nodes responded) factory ApiQueueItem.fromDiscDrop({ required double latitude, @@ -160,6 +186,24 @@ class ApiQueueItem extends HiveObject { /// Convert to API JSON format (matches WebClient exactly) Map toApiJson() { + // For TRACE type, parse the heardRepeats field to extract individual values + if (type == 'TRACE') { + // Format: "repeaterId:localSnr:localRssi:remoteSnr" + final parts = heardRepeats.split(':'); + return { + 'type': type, + 'lat': latitude, + 'lon': longitude, + 'noisefloor': noiseFloor, + 'repeater_id': parts.isNotEmpty ? parts[0] : '', + 'local_snr': parts.length > 1 ? double.tryParse(parts[1]) : null, + 'local_rssi': parts.length > 2 ? int.tryParse(parts[2]) : null, + 'remote_snr': parts.length > 3 ? double.tryParse(parts[3]) : null, + 'timestamp': timestamp.millisecondsSinceEpoch ~/ 1000, + 'external_antenna': externalAntenna, + }; + } + // For DISC type, parse the heardRepeats field to extract individual values if (type == 'DISC') { // Failed discovery (no nodes responded) diff --git a/lib/models/log_entry.dart b/lib/models/log_entry.dart index b4b81a0..f0a468d 100644 --- a/lib/models/log_entry.dart +++ b/lib/models/log_entry.dart @@ -119,6 +119,61 @@ class RxLogEntry { } } +/// Trace Log Entry (targeted zero-hop trace result) +class TraceLogEntry { + final DateTime timestamp; + final double latitude; + final double longitude; + final String targetRepeaterId; + final int? noiseFloor; + final double? localSnr; + final double? remoteSnr; + final int? localRssi; + final bool success; + + TraceLogEntry({ + required this.timestamp, + required this.latitude, + required this.longitude, + required this.targetRepeaterId, + this.noiseFloor, + this.localSnr, + this.remoteSnr, + this.localRssi, + required this.success, + }); + + /// Get formatted timestamp (HH:MM:SS) + String get timeString { + return '${timestamp.hour.toString().padLeft(2, '0')}:' + '${timestamp.minute.toString().padLeft(2, '0')}:' + '${timestamp.second.toString().padLeft(2, '0')}'; + } + + /// Get formatted location (5 decimal places) + String get locationString { + return '${latitude.toStringAsFixed(5)},${longitude.toStringAsFixed(5)}'; + } + + /// Get SNR color severity based on local SNR + SnrSeverity? get severity { + if (localSnr == null) return null; + if (localSnr! <= -1) { + return SnrSeverity.poor; + } else if (localSnr! <= 5) { + return SnrSeverity.fair; + } else { + return SnrSeverity.good; + } + } + + /// Get CSV row + String toCsv() { + return '${timestamp.toIso8601String()},$targetRepeaterId,${localSnr ?? 'null'},${localRssi ?? 'null'},' + '${remoteSnr ?? 'null'},$latitude,$longitude,${noiseFloor ?? ''},$success'; + } +} + /// SNR Severity levels for color coding enum SnrSeverity { poor, // Red: SNR ≤ -1 dB diff --git a/lib/models/noise_floor_session.dart b/lib/models/noise_floor_session.dart index a921216..a1f1fe9 100644 --- a/lib/models/noise_floor_session.dart +++ b/lib/models/noise_floor_session.dart @@ -35,6 +35,12 @@ enum PingEventType { @HiveField(4) discFail, // Grey: Discovery no response + + @HiveField(5) + traceSuccess, // Cyan: Trace got response + + @HiveField(6) + traceFail, // Red: Trace no response } /// Repeater info for graph markers @@ -99,6 +105,8 @@ class PingEventMarker extends HiveObject { PingEventType.rx => Colors.blue, PingEventType.discSuccess => Colors.purple, PingEventType.discFail => Colors.grey, + PingEventType.traceSuccess => Colors.cyan, + PingEventType.traceFail => Colors.red, }; /// Get a display label for this event type @@ -108,6 +116,8 @@ class PingEventMarker extends HiveObject { PingEventType.rx => 'RX', PingEventType.discSuccess => 'DISC Success', PingEventType.discFail => 'DISC Fail', + PingEventType.traceSuccess => 'Trace Success', + PingEventType.traceFail => 'Trace Fail', }; } @@ -154,6 +164,7 @@ class NoiseFloorSession extends HiveObject { String get modeDisplay => switch (mode) { 'active' => 'Active Mode', 'hybrid' => 'Hybrid Mode', + 'targeted' => 'Trace Mode', _ => 'Passive Mode', }; diff --git a/lib/models/ping_data.dart b/lib/models/ping_data.dart index d9d52c8..0e42d08 100644 --- a/lib/models/ping_data.dart +++ b/lib/models/ping_data.dart @@ -139,6 +139,7 @@ class PingStats { final int txCount; final int rxCount; final int discCount; // Discovery count (Passive Mode) + final int traceCount; // Trace count (Targeted Mode) final int successfulUploads; final int failedUploads; final int queuedCount; @@ -147,6 +148,7 @@ class PingStats { this.txCount = 0, this.rxCount = 0, this.discCount = 0, + this.traceCount = 0, this.successfulUploads = 0, this.failedUploads = 0, this.queuedCount = 0, @@ -156,6 +158,7 @@ class PingStats { int? txCount, int? rxCount, int? discCount, + int? traceCount, int? successfulUploads, int? failedUploads, int? queuedCount, @@ -164,6 +167,7 @@ class PingStats { txCount: txCount ?? this.txCount, rxCount: rxCount ?? this.rxCount, discCount: discCount ?? this.discCount, + traceCount: traceCount ?? this.traceCount, successfulUploads: successfulUploads ?? this.successfulUploads, failedUploads: failedUploads ?? this.failedUploads, queuedCount: queuedCount ?? this.queuedCount, diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index e675382..af7c317 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -48,6 +48,8 @@ enum AutoMode { passive, /// Hybrid Mode: Alternates Discovery + Active pings each interval hybrid, + /// Trace Mode: Zero-hop trace to specific repeater + targeted, } /// Result of uploading an offline session @@ -158,6 +160,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { final List _txLogEntries = []; final List _rxLogEntries = []; final List _discLogEntries = []; + final List _traceLogEntries = []; + + // Targeted mode state + String? _targetRepeaterId; // User error log entries final List _errorLogEntries = []; @@ -308,6 +314,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get isPendingDisable => _pingService?.pendingDisable ?? false; /// True when running any mode that does TX (Active or Hybrid) bool get isTxModeRunning => _autoPingEnabled && (_autoMode == AutoMode.active || _autoMode == AutoMode.hybrid); + /// True when running Trace Mode (zero-hop trace) + bool get isTargetedModeRunning => _autoPingEnabled && _autoMode == AutoMode.targeted; + String? get targetRepeaterId => _targetRepeaterId; int get queueSize => _queueSize; int? get currentNoiseFloor => _currentNoiseFloor; int? get currentBatteryPercent => _currentBatteryPercent; @@ -318,6 +327,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { List get txLogEntries => List.unmodifiable(_txLogEntries); List get rxLogEntries => List.unmodifiable(_rxLogEntries); List get discLogEntries => List.unmodifiable(_discLogEntries); + List get traceLogEntries => List.unmodifiable(_traceLogEntries); List get errorLogEntries => List.unmodifiable(_errorLogEntries); ({double lat, double lon})? get mapNavigationTarget => _mapNavigationTarget; int get mapNavigationTrigger => _mapNavigationTrigger; @@ -493,7 +503,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update background service notification with queue size if (_autoPingEnabled) { final modeName = _autoMode == AutoMode.passive ? 'Passive Mode' - : _autoMode == AutoMode.hybrid ? 'Hybrid Mode' : 'Active Mode'; + : _autoMode == AutoMode.hybrid ? 'Hybrid Mode' + : _autoMode == AutoMode.targeted ? 'Trace Mode' : 'Active Mode'; BackgroundServiceManager.updateNotification( mode: modeName, txCount: _pingStats.txCount, @@ -1178,6 +1189,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { }, ); + // Wire UnifiedRxHandler so trace payloads route to TraceTracker + _pingService!.unifiedRxHandler = _unifiedRxHandler; + // Set validation callbacks _pingService!.checkExternalAntennaConfigured = () { // External antenna must be explicitly set (yes or no) before pinging @@ -1251,7 +1265,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update background service notification with current stats if (_autoPingEnabled) { final modeName = _autoMode == AutoMode.passive ? 'Passive Mode' - : _autoMode == AutoMode.hybrid ? 'Hybrid Mode' : 'Active Mode'; + : _autoMode == AutoMode.hybrid ? 'Hybrid Mode' + : _autoMode == AutoMode.targeted ? 'Trace Mode' : 'Active Mode'; BackgroundServiceManager.updateNotification( mode: modeName, txCount: _pingStats.txCount, @@ -1404,6 +1419,53 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ); }; + // Wire up trace ping callback (for log entry creation) + _pingService!.onTracePing = (entry) { + _addTraceLogEntry(entry); + }; + + // Wire up trace window complete callback for noise floor graph + _pingService!.onTraceWindowComplete = (result) { + double? lat; + double? lon; + List? repeaters; + + if (_traceLogEntries.isNotEmpty) { + final lastTrace = _traceLogEntries.first; + lat = lastTrace.latitude; + lon = lastTrace.longitude; + if (result != null && result.success) { + repeaters = [MarkerRepeaterInfo( + repeaterId: result.targetRepeaterId, + snr: result.localSnr, + rssi: result.localRssi, + )]; + // Update the log entry with success data + _traceLogEntries[0] = TraceLogEntry( + timestamp: lastTrace.timestamp, + latitude: lastTrace.latitude, + longitude: lastTrace.longitude, + targetRepeaterId: lastTrace.targetRepeaterId, + noiseFloor: lastTrace.noiseFloor, + localSnr: result.localSnr, + remoteSnr: result.remoteSnr, + localRssi: result.localRssi, + success: true, + ); + notifyListeners(); + } + } + + recordPingEvent( + result != null && result.success + ? PingEventType.traceSuccess + : PingEventType.traceFail, + latitude: lat, + longitude: lon, + repeaters: repeaters, + ); + }; + // Wire up discovery carpeater drop callback (for DiscTracker RSSI failsafe) _pingService!.onDiscCarpeaterDrop = (String repeaterId, String reason) { debugLog('[APP] Discovery carpeater drop: repeater=$repeaterId, reason=$reason'); @@ -2368,14 +2430,21 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { return true; } - /// Toggle auto-ping mode (Active, Passive, or Hybrid) - /// Returns false if blocked by cooldown (Active/Hybrid Mode only - Passive Mode ignores cooldown) + /// Set the target repeater ID for targeted mode + void setTargetRepeaterId(String? id) { + _targetRepeaterId = id; + notifyListeners(); + } + + /// Toggle auto-ping mode (Active, Passive, Hybrid, or Trace) + /// Returns false if blocked by cooldown (Active/Hybrid/Trace Mode only - Passive Mode ignores cooldown) Future toggleAutoPing(AutoMode mode) async { if (_pingService == null) return false; final isPassive = mode == AutoMode.passive; final isHybrid = mode == AutoMode.hybrid; - final isTxMode = !isPassive; // Active and Hybrid both do TX + final isTargeted = mode == AutoMode.targeted; + final isTxMode = !isPassive; // Active, Hybrid, and Targeted all do TX // If currently running the same mode, stop it (always allow stopping) if (_autoPingEnabled && _autoMode == mode) { @@ -2470,7 +2539,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _pingService!.setAutoPingInterval(intervalMs); debugLog('[PING] Using interval from preferences: ${_preferences.autoPingInterval}s (${intervalMs}ms)'); - final started = await _pingService!.enableAutoPing(passiveMode: isPassive, hybridMode: isHybrid); + final started = await _pingService!.enableAutoPing( + passiveMode: isPassive, + hybridMode: isHybrid, + targetedMode: isTargeted, + targetRepeaterId: isTargeted ? _targetRepeaterId : null, + ); if (!started) { // Blocked by cooldown or already enabled if (_pingService!.isInCooldown()) { @@ -2486,7 +2560,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _autoPingEnabled = true; // Start noise floor session for graph tracking - final sessionLabel = isPassive ? 'passive' : isHybrid ? 'hybrid' : 'active'; + final sessionLabel = isPassive ? 'passive' : isHybrid ? 'hybrid' : isTargeted ? 'targeted' : 'active'; _startNoiseFloorSession(sessionLabel); // Enable heartbeat for all auto-ping modes (not offline mode) @@ -2506,7 +2580,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } // Start background service for continuous operation - final modeName = isPassive ? 'Passive Mode' : isHybrid ? 'Hybrid Mode' : 'Active Mode'; + final modeName = isPassive ? 'Passive Mode' : isHybrid ? 'Hybrid Mode' : isTargeted ? 'Trace Mode' : 'Active Mode'; await BackgroundServiceManager.startService( mode: modeName, txCount: _pingStats.txCount, @@ -2532,6 +2606,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _txLogEntries.clear(); _rxLogEntries.clear(); _discLogEntries.clear(); + _traceLogEntries.clear(); _errorLogEntries.clear(); notifyListeners(); } @@ -2546,6 +2621,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { notifyListeners(); } + /// Add a trace log entry (from Trace Mode) + void _addTraceLogEntry(TraceLogEntry entry) { + _traceLogEntries.insert(0, entry); + if (_traceLogEntries.length > _maxLogEntries) { + _traceLogEntries.removeLast(); + } + debugLog('[APP] Trace log entry added: target=${entry.targetRepeaterId}, success=${entry.success}'); + notifyListeners(); + } + /// Log a user-facing error message /// Set [autoSwitch] to false to log without navigating to error log tab void logError(String message, {ErrorSeverity severity = ErrorSeverity.error, bool autoSwitch = true}) { diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index 2610f90..c0581d6 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -13,6 +13,7 @@ import '../models/user_preferences.dart'; import '../providers/app_state_provider.dart'; import '../utils/distance_formatter.dart'; import '../services/bluetooth/bluetooth_service.dart'; +import '../widgets/offline_mode_toggle.dart'; import '../widgets/regional_config_card.dart'; /// BLE device selection and connection screen @@ -394,6 +395,28 @@ class _ConnectionScreenState extends State with WidgetsBinding // Portrait: vertical layout return Column( children: [ + _buildZoneStatusBar(context, appState), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + child: Row( + children: [ + const Expanded(child: OfflineModeToggle()), + const SizedBox(width: 4), + IconButton( + icon: Icon( + Icons.info_outline, + size: 20, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + tooltip: 'About Offline Mode', + onPressed: () => _showOfflineModeInfo(context), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(minWidth: 32, minHeight: 32), + ), + ], + ), + ), Expanded( child: ListView( padding: const EdgeInsets.all(16), @@ -564,6 +587,32 @@ class _ConnectionScreenState extends State with WidgetsBinding ); } + void _showOfflineModeInfo(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.cloud_off, color: Colors.orange, size: 22), + SizedBox(width: 8), + Text('Offline Mode'), + ], + ), + content: const Text( + 'Save pings locally instead of uploading immediately. Useful when you have poor cell connectivity or the API is in maintenance.\n\n' + 'Data is stored on your device and can be uploaded later from the Settings tab when connectivity is restored.', + style: TextStyle(fontSize: 14, height: 1.5), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Got it'), + ), + ], + ), + ); + } + void _showAuthMethodInfo(BuildContext context, String currentType) { showModalBottomSheet( context: context, diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 07711e6..6050b5c 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -880,20 +880,12 @@ class _HomeScreenState extends State { description: 'Sends zero-hop discovery pings every 30s, tracks nearby repeaters and received mesh traffic.', ), - // Offline mode toggle + // Trace Mode _buildHelpItem( - icon: Icons.cloud_off, - color: Colors.orange, - title: 'Offline Mode', - description: 'Save pings locally instead of uploading immediately. Useful when you have poor connectivity. Upload saved sessions later from the Settings tab.', - ), - - // Sound toggle - _buildHelpItem( - icon: Icons.volume_up, - color: Colors.blue, - title: 'Sound', - description: 'Sonar tone when sending TX/Discovery pings. Message tone when receiving valid RX packets, heard repeaters, or discovery responses.', + icon: Icons.gps_fixed, + color: Colors.cyan, + title: 'Trace Mode', + description: 'Sends a zero-hop trace to a specific repeater by its hex ID at your set interval. Shows signal quality (SNR/RSSI) for that one repeater over time — useful for antenna alignment or testing a specific node.', ), const SizedBox(height: 8), diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index 9519772..c8ab642 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -20,7 +20,7 @@ class _LogScreenState extends State with SingleTickerProviderStateMix @override void initState() { super.initState(); - _tabController = TabController(length: 4, vsync: this); + _tabController = TabController(length: 5, vsync: this); } @override @@ -36,8 +36,8 @@ class _LogScreenState extends State with SingleTickerProviderStateMix // Auto-switch to Error tab when requested if (appState.requestErrorLogSwitch) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted && _tabController.index != 3) { - _tabController.animateTo(3); // Switch to Error tab + if (mounted && _tabController.index != 4) { + _tabController.animateTo(4); // Switch to Error tab setState(() {}); } appState.clearErrorLogSwitchRequest(); @@ -78,12 +78,14 @@ class _LogScreenState extends State with SingleTickerProviderStateMix child: Row( children: [ Expanded(child: _buildTabChip(0, 'TX', appState.txLogEntries.length, isTx: true)), - const SizedBox(width: 8), + const SizedBox(width: 6), Expanded(child: _buildTabChip(1, 'RX', appState.rxLogEntries.length, isRx: true)), - const SizedBox(width: 8), + const SizedBox(width: 6), Expanded(child: _buildTabChip(2, 'DISC', appState.discLogEntries.length, isDisc: true)), - const SizedBox(width: 8), - Expanded(child: _buildTabChip(3, 'Errors', appState.errorLogEntries.length, isError: true)), + const SizedBox(width: 6), + Expanded(child: _buildTabChip(3, 'TRC', appState.traceLogEntries.length, isTrace: true)), + const SizedBox(width: 6), + Expanded(child: _buildTabChip(4, 'Err', appState.errorLogEntries.length, isError: true)), ], ), ), @@ -95,6 +97,7 @@ class _LogScreenState extends State with SingleTickerProviderStateMix _TxLogTab(entries: appState.txLogEntries), _RxLogTab(entries: appState.rxLogEntries), _DiscLogTab(entries: appState.discLogEntries), + _TraceLogTab(entries: appState.traceLogEntries), _ErrorLogTab(entries: appState.errorLogEntries), ], ), @@ -105,12 +108,13 @@ class _LogScreenState extends State with SingleTickerProviderStateMix } /// Build a tab chip that matches StatusBar chip styling - Widget _buildTabChip(int index, String label, int count, {bool isError = false, bool isDisc = false, bool isTx = false, bool isRx = false}) { + Widget _buildTabChip(int index, String label, int count, {bool isError = false, bool isDisc = false, bool isTx = false, bool isRx = false, bool isTrace = false}) { final theme = Theme.of(context); // Colors matching status bar chips const discColor = Color(0xFF7B68EE); // DISC purple const txColor = Colors.green; // TX green (matches status bar) const rxColor = Colors.blue; // RX blue (matches status bar) + const traceColor = Colors.cyan; // TRC cyan (matches noise floor chart) return GestureDetector( onTap: () { @@ -127,6 +131,8 @@ class _LogScreenState extends State with SingleTickerProviderStateMix currentColor = Colors.red; } else if (isDisc) { currentColor = discColor; + } else if (isTrace) { + currentColor = traceColor; } else if (isTx) { currentColor = txColor; } else if (isRx) { @@ -150,12 +156,16 @@ class _LogScreenState extends State with SingleTickerProviderStateMix child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - label, - style: TextStyle( - fontSize: 12, - fontWeight: isCurrentlySelected ? FontWeight.w600 : FontWeight.w500, - color: currentColor, + Flexible( + child: Text( + label, + overflow: TextOverflow.clip, + softWrap: false, + style: TextStyle( + fontSize: 12, + fontWeight: isCurrentlySelected ? FontWeight.w600 : FontWeight.w500, + color: currentColor, + ), ), ), if (count > 0) ...[ @@ -197,7 +207,10 @@ class _LogScreenState extends State with SingleTickerProviderStateMix case 2: // DISC Log _copyDiscLogToCsv(context, appState.discLogEntries); break; - case 3: // Error Log + case 3: // TRC Log + _copyTraceLogToCsv(context, appState.traceLogEntries); + break; + case 4: // Error Log _copyErrorLogToCsv(context, appState.errorLogEntries); break; } @@ -260,6 +273,25 @@ class _LogScreenState extends State with SingleTickerProviderStateMix ); } + void _copyTraceLogToCsv(BuildContext context, List entries) { + if (entries.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('No trace log entries to copy'), duration: Duration(seconds: 2)), + ); + return; + } + + final buffer = StringBuffer(); + buffer.writeln('timestamp,target_repeater,local_snr,local_rssi,remote_snr,latitude,longitude,noisefloor,success'); + for (final entry in entries) { + buffer.writeln(entry.toCsv()); + } + Clipboard.setData(ClipboardData(text: buffer.toString())); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Trace log copied to clipboard'), duration: Duration(seconds: 2)), + ); + } + void _copyErrorLogToCsv(BuildContext context, List entries) { if (entries.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( @@ -284,7 +316,7 @@ class _LogScreenState extends State with SingleTickerProviderStateMix context: context, builder: (context) => AlertDialog( title: const Text('Clear All Logs?'), - content: const Text('This will clear TX, RX, DISC, and error logs.'), + content: const Text('This will clear TX, RX, DISC, TRC, and error logs.'), actions: [ TextButton( onPressed: () => Navigator.pop(context), @@ -1063,6 +1095,304 @@ class _DiscLogTab extends StatelessWidget { } } +/// Trace Log Tab (Trace Mode results) +class _TraceLogTab extends StatelessWidget { + final List entries; + + const _TraceLogTab({required this.entries}); + + @override + Widget build(BuildContext context) { + if (entries.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.gps_fixed, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.3)), + const SizedBox(height: 16), + Text( + 'No trace results yet', + style: TextStyle( + fontSize: 16, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: 8), + Text( + 'Enter a repeater ID and start Trace Mode', + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.7), + ), + ), + ], + ), + ); + } + + return ListView.builder( + padding: const EdgeInsets.all(12), + itemCount: entries.length, + itemBuilder: (context, index) { + return _buildTraceEntry(context, entries[index]); + }, + ); + } + + Widget _buildTraceEntry(BuildContext context, TraceLogEntry entry) { + final colorScheme = Theme.of(context).colorScheme; + final appState = context.read(); + + return Card( + margin: const EdgeInsets.only(bottom: 8), + color: colorScheme.surfaceContainerHigh, + child: InkWell( + onTap: () { + appState.navigateToMapCoordinates(entry.latitude, entry.longitude); + }, + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header row: Time and repeater ID (matching disc style) + Row( + children: [ + // Time badge (neutral, matching disc) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(6), + ), + child: Text( + entry.timeString, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: colorScheme.onSurface, + ), + ), + ), + const Spacer(), + // Repeater ID + success/fail text + Text( + entry.targetRepeaterId, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(width: 6), + Text( + entry.success ? 'responded' : 'no response', + style: TextStyle( + fontSize: 11, + color: colorScheme.onSurfaceVariant, + fontFamily: 'monospace', + ), + ), + ], + ), + const SizedBox(height: 8), + + // Location + Row( + children: [ + Icon(Icons.location_on, size: 14, color: colorScheme.onSurfaceVariant), + const SizedBox(width: 4), + Text( + entry.locationString, + style: TextStyle( + fontSize: 11, + color: colorScheme.onSurfaceVariant, + fontFamily: 'monospace', + ), + ), + ], + ), + + // Results table (matching disc style) + if (entry.success) ...[ + const SizedBox(height: 10), + Container( + decoration: BoxDecoration( + color: colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: colorScheme.outline.withValues(alpha: 0.5)), + ), + child: Column( + children: [ + // Header row + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + child: Row( + children: [ + SizedBox( + width: 50, + child: Text( + 'Node', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'RX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'RX RSSI', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'TX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + ], + ), + ), + Divider(height: 1, color: Theme.of(context).dividerColor), + // Data row + _buildTraceNodeRow(context, entry), + ], + ), + ), + ] else ...[ + const SizedBox(height: 8), + Text( + 'No response', + style: TextStyle( + fontSize: 11, + color: colorScheme.onSurfaceVariant, + fontStyle: FontStyle.italic, + ), + ), + ], + ], + ), + ), + ), + ); + } + + /// Build the data row for a trace result (matching disc node row style) + Widget _buildTraceNodeRow(BuildContext context, TraceLogEntry entry) { + // RX SNR color + final rxSnr = entry.localSnr; + Color rxSnrColor; + if (rxSnr == null) { + rxSnrColor = Colors.grey; + } else if (rxSnr <= -1) { + rxSnrColor = Colors.red; + } else if (rxSnr <= 5) { + rxSnrColor = Colors.orange; + } else { + rxSnrColor = Colors.green; + } + + // RSSI color + final rssi = entry.localRssi; + Color rssiColor; + if (rssi == null) { + rssiColor = Colors.grey; + } else if (rssi >= -70) { + rssiColor = Colors.green; + } else if (rssi >= -100) { + rssiColor = Colors.orange; + } else { + rssiColor = Colors.red; + } + + // TX SNR color (remote) + final txSnr = entry.remoteSnr; + Color txSnrColor; + if (txSnr == null) { + txSnrColor = Colors.grey; + } else if (txSnr <= -1) { + txSnrColor = Colors.red; + } else if (txSnr <= 5) { + txSnrColor = Colors.orange; + } else { + txSnrColor = Colors.green; + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: Row( + children: [ + SizedBox( + width: 50, + child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 11), + ), + Expanded( + child: Center( + child: _buildChip(rxSnr?.toStringAsFixed(1) ?? '-', rxSnrColor), + ), + ), + Expanded( + child: Center( + child: _buildChip(rssi != null ? '$rssi' : '-', rssiColor), + ), + ), + Expanded( + child: Center( + child: _buildChip(txSnr?.toStringAsFixed(1) ?? '-', txSnrColor), + ), + ), + ], + ), + ); + } + + /// Build a small colored chip for table cells (matching disc style) + Widget _buildChip(String value, Color color) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: color.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(4), + border: Border.all(color: color.withValues(alpha: 0.4)), + ), + child: Text( + value, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: color, + fontFamily: 'monospace', + ), + ), + ); + } +} + /// Error Log Tab class _ErrorLogTab extends StatelessWidget { final List entries; diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 85de123..8913478 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -137,6 +137,15 @@ class _SettingsScreenState extends State { // Wardriving Settings section _buildSectionHeader(context, 'Wardriving Settings'), + // Sound Notifications Toggle + SwitchListTile( + secondary: Icon(appState.isSoundEnabled ? Icons.volume_up : Icons.volume_off), + title: const Text('Sound Notifications'), + subtitle: Text(appState.isSoundEnabled ? 'Plays on ping events' : 'Silent'), + value: appState.isSoundEnabled, + onChanged: (_) => appState.toggleSoundEnabled(), + ), + // Auto-Ping Interval Selector ListTile( leading: const Icon(Icons.timer), diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index b03ab9f..613fc5b 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -347,6 +347,53 @@ class ApiQueueService { }); } + /// Enqueue a TRACE ping result (targeted zero-hop trace) + Future enqueueTrace({ + required double latitude, + required double longitude, + required String repeaterId, + required double localSnr, + required int localRssi, + required double remoteSnr, + required int timestamp, + required bool externalAntenna, + int? noiseFloor, + }) async { + final item = ApiQueueItem.fromTrace( + latitude: latitude, + longitude: longitude, + repeaterId: repeaterId, + localSnr: localSnr, + localRssi: localRssi, + remoteSnr: remoteSnr, + timestamp: timestamp, + externalAntenna: externalAntenna, + noiseFloor: noiseFloor, + ); + + // In offline mode, accumulate to offline pings list instead of queue + if (offlineMode) { + _offlinePings.add(item.toApiJson()); + debugLog('[API QUEUE] TRACE enqueued (offline): $repeaterId'); + return; + } + + final wrote = await _safeWrite((box) => box.add(item)); + if (!wrote) { + _memoryQueue.add(item); + debugLog('[API QUEUE] TRACE enqueued (memory fallback): $repeaterId at $latitude, $longitude (queue size: $queueSize)'); + } else { + debugLog('[API QUEUE] TRACE enqueued: $repeaterId at $latitude, $longitude (queue size: $queueSize)'); + } + onQueueUpdated?.call(queueSize); + _pingFlushTimer?.cancel(); + _pingFlushTimer = Timer(const Duration(seconds: 5), () { + debugLog('[API QUEUE] Ping flush timer fired'); + _flushRxBuffer(); + _uploadBatch(); + }); + } + /// Enqueue a failed DISC discovery (no nodes responded) Future enqueueDiscDrop({ required double latitude, diff --git a/lib/services/background_service.dart b/lib/services/background_service.dart index 49a110c..3ff0d17 100644 --- a/lib/services/background_service.dart +++ b/lib/services/background_service.dart @@ -249,6 +249,8 @@ class BackgroundServiceManager { String body; if (mode == 'Passive Mode') { body = 'RX: $rxCount | Queue: $queueSize'; + } else if (mode == 'Trace Mode') { + body = 'Trace: $txCount | RX: $rxCount | Queue: $queueSize'; } else { body = 'TX: $txCount | RX: $rxCount | Queue: $queueSize'; } diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index 5594b2f..f3fdaca 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -68,6 +68,7 @@ class MeshCoreConnection { final _rawDataController = StreamController>.broadcast(); final _logRxDataController = StreamController<({Uint8List raw, double snr, int rssi})>.broadcast(); final _controlDataController = StreamController<({Uint8List raw, double snr, int rssi})>.broadcast(); + final _traceDataController = StreamController.broadcast(); final _noiseFloorController = StreamController.broadcast(); final _batteryController = StreamController.broadcast(); @@ -122,6 +123,10 @@ class MeshCoreConnection { /// Stream of ControlData packets (for discovery responses) Stream<({Uint8List raw, double snr, int rssi})> get controlDataStream => _controlDataController.stream; + /// Stream of TraceData packets (for trace path responses) + /// 0x89 has NO snr/rssi prefix — raw bytes are the trace payload directly + Stream get traceDataStream => _traceDataController.stream; + /// Stream of noise floor updates (dBm) Stream get noiseFloorStream => _noiseFloorController.stream; @@ -401,6 +406,9 @@ class MeshCoreConnection { case PushCodes.controlData: _onControlDataPush(reader); break; + case PushCodes.traceData: + _onTraceDataPush(reader); + break; case ResponseCodes.stats: _onStatsResponse(reader); break; @@ -609,6 +617,17 @@ class MeshCoreConnection { _controlDataController.add((raw: raw, snr: snr, rssi: rssi)); } + void _onTraceDataPush(BufferReader reader) { + // 0x89 TraceData has NO snr/rssi prefix (unlike 0x88 LogRxData). + // The entire remaining payload is the trace response: + // [reserved][path_len][flags][tag:4][auth:4][path_hashes][path_snrs] + final raw = reader.readRemainingBytes(); + + debugLog('[CONN] Received trace data: ${raw.length} bytes'); + + _traceDataController.add(raw); + } + void _onStatsResponse(BufferReader reader) { // Stats response format (from web client): // @@ -955,6 +974,27 @@ class MeshCoreConnection { return tag; } + /// Send trace path to a specific repeater (targeted ping / zero-hop trace) + /// Returns the 4-byte tag used for matching the response + Future sendTracePath(Uint8List repeaterIdBytes) async { + final random = Random.secure(); + final tag = Uint8List.fromList([ + random.nextInt(256), random.nextInt(256), + random.nextInt(256), random.nextInt(256), + ]); + + debugLog('[CONN] Sending trace to ${repeaterIdBytes.map((b) => b.toRadixString(16).padLeft(2, "0")).join("")}'); + + final data = BufferWriter(); + data.writeByte(CommandCodes.sendTracePath); // 0x24 + data.writeBytes(tag); // 4-byte tag + data.writeUInt32LE(0); // auth_code = 0 + data.writeByte(0); // flags = 0 + data.writeBytes(repeaterIdBytes); // target repeater ID + await _sendToRadio(data); + return tag; + } + /// Get battery voltage Future getBatteryVoltage() async { final data = BufferWriter(); @@ -1108,6 +1148,7 @@ class MeshCoreConnection { _rawDataController.close(); _logRxDataController.close(); _controlDataController.close(); + _traceDataController.close(); _noiseFloorController.close(); _batteryController.close(); } diff --git a/lib/services/meshcore/packet_metadata.dart b/lib/services/meshcore/packet_metadata.dart index a6dcc0a..c65a6ba 100644 --- a/lib/services/meshcore/packet_metadata.dart +++ b/lib/services/meshcore/packet_metadata.dart @@ -162,6 +162,12 @@ class PacketMetadata { return payloadType == PayloadType.advert; } + /// Check if packet is TRACE (trace path response, header 0x26) + bool get isTrace { + final payloadType = (header >> PacketHeader.typeShift) & PacketHeader.typeMask; + return payloadType == PayloadType.trace; + } + /// Get first hop as hex string (for TX tracking keys) /// Returns multi-byte hex (2/4/6/8 chars depending on pathHashSize) String? get firstHopHex { diff --git a/lib/services/meshcore/trace_tracker.dart b/lib/services/meshcore/trace_tracker.dart new file mode 100644 index 0000000..09c1358 --- /dev/null +++ b/lib/services/meshcore/trace_tracker.dart @@ -0,0 +1,212 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import '../../utils/debug_logger_io.dart'; + +/// Result of a trace path probe to a specific repeater +class TraceResult { + final String targetRepeaterId; + final double localSnr; // SNR we measured on the return (path_snrs[1] / 4.0) + final int localRssi; // RSSI from BLE event metadata + final double remoteSnr; // SNR the repeater measured (path_snrs[0] / 4.0) + final bool success; + + const TraceResult({ + required this.targetRepeaterId, + required this.localSnr, + required this.localRssi, + required this.remoteSnr, + required this.success, + }); +} + +/// Trace path tracker for targeted ping (zero-hop trace) +/// Sends CMD_SEND_TRACE_PATH (0x24) to a specific repeater and listens +/// for the trace response (PUSH_CODE_TRACE_DATA, 0x89). +/// +/// Follows the DiscTracker pattern but simpler: expects exactly 1 response. +class TraceTracker { + bool isListening = false; + Uint8List? _expectedTag; + String _targetRepeaterId = ''; + TraceResult? _result; + Timer? _windowTimer; + + /// BLE metadata from the 0x88 LogRxData event that arrives before the 0x89 TraceData. + /// Set by UnifiedRxHandler when it sees a trace packet in the LogRxData stream. + double pendingBleSnr = 0.0; + int pendingBleRssi = 0; + + /// Fired when a trace response is received during the window + void Function(TraceResult)? onTraceReceived; + + /// Fired when the listening window ends (result is null if no response) + void Function(TraceResult?)? onWindowComplete; + + TraceTracker(); + + /// Start tracking trace responses + void startTracking({ + required Uint8List tag, + required String targetRepeaterId, + int hopBytes = 1, + Duration windowDuration = const Duration(seconds: 7), + }) { + debugLog('[TRACE] Starting trace tracking for repeater $targetRepeaterId'); + debugLog('[TRACE] Tag: ${tag.map((b) => b.toRadixString(16).padLeft(2, '0')).join('')}'); + + isListening = true; + _expectedTag = tag; + _targetRepeaterId = targetRepeaterId; + _result = null; + pendingBleSnr = 0.0; + pendingBleRssi = 0; + + // Start window timer + _windowTimer?.cancel(); + _windowTimer = Timer(windowDuration, _endWindow); + + debugLog('[TRACE] Trace tracking window started (${windowDuration.inSeconds}s)'); + } + + /// Handle incoming trace data packet (0x89) + /// Returns true if the packet was a valid trace response + /// + /// Trace response format (per meshcore_py reference): + /// Byte 0: reserved (skip) + /// Byte 1: path_len (raw byte count of path hashes, NOT LogRxData encoding) + /// Byte 2: flags → hashSize = 1 << (flags & 3) + /// Bytes 3-6: tag → match against _expectedTag + /// Bytes 7-10: auth_code (skip) + /// Bytes 11 to 11+path_len: path_hashes → extract repeater ID + /// Next hopCount+1 bytes: path_snrs → each is signedInt8 / 4.0 for dB + /// For zero-hop (hopCount=1): remoteSnr = snrs[0], localSnr = snrs[1] + bool handlePacket(Uint8List rawBytes, double bleSnr, int bleRssi) { + if (!isListening) return false; + + try { + // Minimum: 1 (reserved) + 1 (path_len) + 1 (flags) + 4 (tag) + 4 (auth) = 11 bytes + if (rawBytes.length < 11) { + debugLog('[TRACE] Packet too short: ${rawBytes.length} bytes (need at least 11)'); + return false; + } + + // Skip byte 0 (reserved) + final pathLen = rawBytes[1]; // Raw byte count of path hashes + final flags = rawBytes[2]; + + // Decode per 0x89 trace format (meshcore_py reference): + // hash size from flags, hop count from path_len / hash_size + final hashSize = 1 << (flags & 3); // 1, 2, 4, or 8 bytes per hop + final hopCount = hashSize > 0 ? pathLen ~/ hashSize : 0; + + debugLog('[TRACE] pathLen=0x${pathLen.toRadixString(16)}, hashSize=$hashSize, hopCount=$hopCount'); + + // Extract tag (bytes 3-6) + final tag = rawBytes.sublist(3, 7); + + // Match tag against expected + final expectedTag = _expectedTag; + if (expectedTag != null) { + bool tagMatch = true; + for (int i = 0; i < 4; i++) { + if (tag[i] != expectedTag[i]) { + tagMatch = false; + break; + } + } + if (!tagMatch) { + debugLog('[TRACE] Tag mismatch, ignoring packet'); + return false; + } + } + + // Skip auth_code (bytes 7-10) + + // Extract path hashes (bytes 11 to 11 + hopCount*hashSize) + const pathStart = 11; + final pathEnd = pathStart + (hopCount * hashSize); + + if (rawBytes.length < pathEnd) { + debugLog('[TRACE] Packet too short for path hashes: need $pathEnd, have ${rawBytes.length}'); + return false; + } + + // Extract repeater ID from first hop in path + String repeaterId = ''; + if (hopCount > 0) { + final idBytes = rawBytes.sublist(pathStart, pathStart + hashSize); + repeaterId = idBytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join('').toUpperCase(); + } + + // Extract path SNRs (hopCount+1 bytes after path hashes) + final snrStart = pathEnd; + final snrEnd = snrStart + hopCount + 1; + + double remoteSnr = 0.0; + double localSnr = bleSnr; // Default to BLE metadata SNR + + if (rawBytes.length >= snrEnd && hopCount >= 1) { + // Each SNR byte is signed int8, divide by 4.0 for dB + remoteSnr = rawBytes[snrStart].toSigned(8) / 4.0; + if (hopCount + 1 >= 2) { + localSnr = rawBytes[snrStart + 1].toSigned(8) / 4.0; + } + } + + debugLog('[TRACE] Trace response from $repeaterId: ' + 'localSnr=${localSnr.toStringAsFixed(2)}, ' + 'remoteSnr=${remoteSnr.toStringAsFixed(2)}, ' + 'bleRssi=$bleRssi'); + + _result = TraceResult( + targetRepeaterId: _targetRepeaterId, + localSnr: localSnr, + localRssi: bleRssi, + remoteSnr: remoteSnr, + success: true, + ); + + // Notify callback + onTraceReceived?.call(_result!); + + return true; + } catch (e, stackTrace) { + debugError('[TRACE] Error processing trace response: $e'); + debugError('[TRACE] Stack trace: $stackTrace'); + return false; + } + } + + /// Stop tracking and return result + TraceResult? stopTracking() { + debugLog('[TRACE] Stopping trace tracking (result: ${_result != null ? 'received' : 'none'})'); + + final result = _result; + isListening = false; + _windowTimer?.cancel(); + _windowTimer = null; + _expectedTag = null; + + return result; + } + + /// Handle trace window completion + void _endWindow() { + debugLog('[TRACE] Trace window ended (result: ${_result != null ? 'success' : 'no response'})'); + + final result = _result; + isListening = false; + _windowTimer = null; + _expectedTag = null; + pendingBleSnr = 0.0; + pendingBleRssi = 0; + + onWindowComplete?.call(result); + } + + /// Dispose of resources + void dispose() { + stopTracking(); + } +} diff --git a/lib/services/meshcore/unified_rx_handler.dart b/lib/services/meshcore/unified_rx_handler.dart index 6e92b74..1c95dd2 100644 --- a/lib/services/meshcore/unified_rx_handler.dart +++ b/lib/services/meshcore/unified_rx_handler.dart @@ -4,6 +4,7 @@ import '../../utils/debug_logger_io.dart'; import 'packet_metadata.dart'; import 'packet_validator.dart'; import 'rx_logger.dart'; +import 'trace_tracker.dart'; import 'tx_tracker.dart'; /// Unified RX handler - orchestrates TX echo tracking and passive RX logging @@ -18,6 +19,9 @@ class UnifiedRxHandler { /// Get current validator PacketValidator get validator => _validator; + /// Trace tracker for targeted ping mode (set by PingService when active) + TraceTracker? traceTracker; + /// Channel key for message decryption (injected for TX validation) Uint8List? channelKey; @@ -72,7 +76,20 @@ class UnifiedRxHandler { debugLog('[UNIFIED RX] Packet received: ' 'header=0x${metadata.header.toRadixString(16)}, ' 'pathHashSize=${metadata.pathHashSize}, pathHashCount=${metadata.pathHashCount}'); - + + // Store BLE metadata from 0x88 LogRxData for trace packets. + // The actual trace payload arrives separately via 0x89 TraceData stream. + // We only store RSSI/SNR here — the 0x89 handler combines them. + if (metadata.isTrace) { + final tt = traceTracker; + if (tt != null && tt.isListening) { + debugLog('[UNIFIED RX] Trace packet in 0x88 - storing BLE metadata for 0x89 handler'); + tt.pendingBleSnr = metadata.snr; + tt.pendingBleRssi = metadata.rssi; + } + return; // Trace packets don't go to TX tracker or RX logger + } + // Route to TX tracking if active (during 5s echo window) if (txTracker.isListening) { debugLog('[UNIFIED RX] TX tracking active - checking for echo'); diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index cee2547..5854468 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:typed_data'; import 'package:geolocator/geolocator.dart'; @@ -12,7 +13,9 @@ import 'countdown_timer_service.dart'; import 'gps_service.dart'; import 'meshcore/connection.dart'; import 'meshcore/disc_tracker.dart'; +import 'meshcore/trace_tracker.dart'; import 'meshcore/tx_tracker.dart'; +import 'meshcore/unified_rx_handler.dart'; import 'wakelock_service.dart'; /// Ping service for TX/RX ping orchestration @@ -70,6 +73,9 @@ class PingService { /// When true, skip RSSI carpeater check in DiscTracker (user setting) bool disableRssiFilter; + /// Unified RX handler reference for routing trace packets + UnifiedRxHandler? unifiedRxHandler; + PingStats _stats = const PingStats(); DateTime? _lastTxTime; Timer? _rxWindowTimer; @@ -86,9 +92,17 @@ class PingService { bool _autoPingEnabled = false; bool _passiveModeEnabled = false; bool _hybridModeEnabled = false; + bool _targetedModeEnabled = false; bool _nextPingIsDiscovery = true; // Start hybrid with discovery Timer? _autoTimer; + // Targeted mode tracking + TraceTracker? _traceTracker; + StreamSubscription? _traceDataSubscription; + Timer? _targetedTimer; + String? _targetRepeaterId; + Position? _lastTargetedPosition; + // Pending disable flag - when true, disable will execute after RX window ends bool _pendingDisable = false; @@ -144,6 +158,13 @@ class PingService { /// Parameters: (bool success) - true if any nodes discovered, false if none void Function(bool success)? onDiscoveryWindowComplete; + /// Callback when trace window ends (for noise floor graph + log) + /// Parameters: (TraceResult? result) - null if no response + void Function(TraceResult? result)? onTraceWindowComplete; + + /// Callback when trace ping is sent (for log entry creation) + void Function(TraceLogEntry)? onTracePing; + /// Callback when pingInProgress changes (for immediate UI refresh) void Function()? onPingProgressChanged; @@ -201,6 +222,9 @@ class PingService { /// Check if Hybrid Mode is active (alternates discovery + TX) bool get isHybridMode => _hybridModeEnabled; + /// Check if Targeted Mode is active (zero-hop trace to specific repeater) + bool get isTargetedMode => _targetedModeEnabled; + /// Check if discovery tracker is currently listening (for Passive Mode UI) bool get isDiscoveryListening => _discTracker?.isListening ?? false; @@ -707,9 +731,11 @@ class PingService { debugLog('[PING] Executing pending disable after RX window'); _pendingDisable = false; final wasHybrid = _hybridModeEnabled; + final wasTargeted = _targetedModeEnabled; _autoPingEnabled = false; _passiveModeEnabled = false; _hybridModeEnabled = false; + _targetedModeEnabled = false; _nextPingIsDiscovery = true; _autoTimer?.cancel(); _autoTimer = null; @@ -717,6 +743,10 @@ class PingService { if (wasHybrid) { _stopDiscoveryMode(); } + // Clean up targeted infrastructure if targeted was enabled + if (wasTargeted) { + _stopTargetedMode(); + } // Start cooldown immediately _cooldownTimer.start(_autoPingCooldown.inMilliseconds); debugLog('[PING] Pending disable complete, cooldown started'); @@ -809,20 +839,34 @@ class PingService { } } - /// Enable Active Mode (timer-based auto ping), Passive Mode (listen-only), or Hybrid Mode + /// Enable Active Mode (timer-based auto ping), Passive Mode (listen-only), + /// Hybrid Mode, or Targeted Mode (zero-hop trace) /// Reference: startAutoPing() in wardrive.js /// @param passiveMode - If true, only listens for RX (no TX pings) - this is Passive Mode /// @param hybridMode - If true, alternates discovery + TX pings each interval - Future enableAutoPing({bool passiveMode = false, bool hybridMode = false}) async { - debugLog('[AUTO] enableAutoPing called (passiveMode=$passiveMode, hybridMode=$hybridMode)'); + /// @param targetedMode - If true, sends trace path to specific repeater + /// @param targetRepeaterId - Repeater ID hex string (required when targetedMode=true) + Future enableAutoPing({ + bool passiveMode = false, + bool hybridMode = false, + bool targetedMode = false, + String? targetRepeaterId, + }) async { + debugLog('[AUTO] enableAutoPing called (passiveMode=$passiveMode, hybridMode=$hybridMode, targetedMode=$targetedMode)'); if (_autoPingEnabled) { debugLog('[AUTO] Auto mode already enabled'); return false; } + // Targeted mode requires a repeater ID + if (targetedMode && (targetRepeaterId == null || targetRepeaterId.isEmpty)) { + debugLog('[AUTO] Targeted mode requires a repeater ID'); + return false; + } + // Check if we're in cooldown (can't start during cooldown) - // Hybrid and Active modes are blocked by cooldown, Passive is not + // Hybrid, Active, and Targeted modes are blocked by cooldown, Passive is not // Reference: isInCooldown() check in startAutoPing() in wardrive.js if (!passiveMode && isInCooldown()) { final remainingSec = getRemainingCooldownSeconds(); @@ -840,14 +884,23 @@ class PingService { _autoPingEnabled = true; _passiveModeEnabled = passiveMode; _hybridModeEnabled = hybridMode; + _targetedModeEnabled = targetedMode; _nextPingIsDiscovery = true; // Always start hybrid with discovery + if (targetedMode) { + _targetRepeaterId = targetRepeaterId; + } + // Enable wake lock to keep screen on during auto mode // Reference: acquireWakeLock() in wardrive.js debugLog('[AUTO] Acquiring wake lock for auto mode'); await _wakelockService.enable(); - if (hybridMode) { + if (targetedMode) { + // Targeted Mode: send trace path to specific repeater + debugLog('[TARGETED] Targeted Mode started - tracing repeater $targetRepeaterId'); + await _startTargetedMode(); + } else if (hybridMode) { // Hybrid Mode: set up discovery infrastructure, then start with discovery debugLog('[HYBRID] Hybrid Mode started - alternating discovery + TX pings'); await _startDiscoveryMode(); @@ -905,9 +958,15 @@ class PingService { _stopDiscoveryMode(); } + // Clean up targeted mode infrastructure + if (_targetedModeEnabled) { + _stopTargetedMode(); + } + _autoPingEnabled = false; _passiveModeEnabled = false; _hybridModeEnabled = false; + _targetedModeEnabled = false; _nextPingIsDiscovery = true; // Disable wake lock when auto mode stops @@ -928,8 +987,10 @@ class PingService { _autoPingEnabled = false; _passiveModeEnabled = false; _hybridModeEnabled = false; + _targetedModeEnabled = false; _nextPingIsDiscovery = true; _stopDiscoveryMode(); + _stopTargetedMode(); await _wakelockService.disable(); } @@ -1231,6 +1292,219 @@ class PingService { }); } + // ============================================ + // Targeted Mode (Zero-Hop Trace) + // ============================================ + + /// Start targeted mode - subscribes to trace data and sends first trace + Future _startTargetedMode() async { + debugLog('[TRACE] Starting targeted mode for repeater $_targetRepeaterId'); + + // Create trace tracker + final tracker = TraceTracker(); + _traceTracker = tracker; + tracker.onTraceReceived = (result) { + debugLog('[TRACE] Trace response received: localSnr=${result.localSnr}, remoteSnr=${result.remoteSnr}'); + }; + tracker.onWindowComplete = (result) { + debugLog('[TRACE] Trace window complete: ${result != null ? 'success' : 'no response'}'); + _handleTraceWindowComplete(result); + }; + + // Wire trace tracker into UnifiedRxHandler so 0x88 BLE metadata + // gets stored for the 0x89 handler + unifiedRxHandler?.traceTracker = tracker; + + // Subscribe to 0x89 TraceData stream for actual trace payloads + _traceDataSubscription = _connection.traceDataStream.listen((raw) { + final tt = _traceTracker; + if (tt != null && tt.isListening) { + tt.handlePacket(raw, tt.pendingBleSnr, tt.pendingBleRssi); + } + }); + + // Send first trace immediately + await _sendTargetedPing(); + } + + /// Stop targeted mode - cleans up tracker and subscription + void _stopTargetedMode() { + debugLog('[TRACE] Stopping targeted mode'); + _targetedTimer?.cancel(); + _targetedTimer = null; + _traceDataSubscription?.cancel(); + _traceDataSubscription = null; + unifiedRxHandler?.traceTracker = null; + _traceTracker?.dispose(); + _traceTracker = null; + _lastTargetedPosition = null; + } + + /// Send a targeted ping (trace path) and start listening window + Future _sendTargetedPing() async { + if (!_autoPingEnabled || !_targetedModeEnabled) { + debugLog('[TRACE] Not in targeted mode, skipping trace'); + return; + } + + final targetId = _targetRepeaterId; + if (targetId == null || targetId.isEmpty) { + debugLog('[TRACE] No target repeater ID, skipping trace'); + _scheduleNextTargetedPing(); + return; + } + + // Check GPS + final position = _gpsService.lastPosition; + if (position == null) { + debugLog('[TRACE] No GPS position, skipping trace'); + _pingInProgress = false; + _scheduleNextTargetedPing(); + return; + } + + // Check minimum distance from last trace (25m) + final lastPos = _lastTargetedPosition; + if (lastPos != null) { + final distance = Geolocator.distanceBetween( + lastPos.latitude, lastPos.longitude, + position.latitude, position.longitude, + ); + if (distance < _gpsService.configuredMinDistance) { + debugLog('[TRACE] Too close to last trace (${distance.toStringAsFixed(1)}m < ${_gpsService.configuredMinDistance.toInt()}m), skipping'); + _skipReason = 'too close'; + _pingInProgress = false; + _scheduleNextTargetedPing(); + return; + } + } + + // Clear skip reason since we're proceeding + _skipReason = null; + + // Signal "Sending..." to UI + _pingInProgress = true; + onPingProgressChanged?.call(); + + // Capture noise floor + final noiseFloor = _connection.lastNoiseFloor; + _pendingTxNoiseFloor = noiseFloor; + + // Create trace log entry immediately + final traceEntry = TraceLogEntry( + timestamp: DateTime.now(), + latitude: position.latitude, + longitude: position.longitude, + targetRepeaterId: targetId, + noiseFloor: noiseFloor, + success: false, // Will be updated after window completes + ); + onTracePing?.call(traceEntry); + + debugLog('[TRACE] Sending trace to $targetId at ${position.latitude.toStringAsFixed(5)}, ${position.longitude.toStringAsFixed(5)}'); + + try { + // Play transmit sound + _audioService?.playTransmitSound(); + + // Convert hex repeater ID to bytes + final repeaterIdBytes = Uint8List(_hopBytes); + for (int i = 0; i < _hopBytes && i * 2 + 2 <= targetId.length; i++) { + repeaterIdBytes[i] = int.parse(targetId.substring(i * 2, i * 2 + 2), radix: 16); + } + + // Send trace path and get tag + final tag = await _connection.sendTracePath(repeaterIdBytes); + + // Start tracking with the tag + _traceTracker?.startTracking( + tag: tag, + targetRepeaterId: targetId, + hopBytes: _hopBytes, + windowDuration: _rxListeningWindow, + ); + + // Start listening window countdown display + _discoveryWindowCountdown.start(_rxListeningWindow.inMilliseconds); + + // Clear pingInProgress now that trace window is active + _pingInProgress = false; + + // Update last targeted position for 25m check + _lastTargetedPosition = position; + + } catch (e) { + _pingInProgress = false; + debugError('[TRACE] Failed to send trace: $e'); + _scheduleNextTargetedPing(); + } + } + + /// Handle trace window completion + void _handleTraceWindowComplete(TraceResult? result) { + _discoveryWindowCountdown.stop(); + final position = _lastTargetedPosition; + final targetId = _targetRepeaterId ?? ''; + + if (result != null && result.success && position != null) { + debugLog('[TRACE] Trace successful: localSnr=${result.localSnr}, remoteSnr=${result.remoteSnr}'); + + // Queue to API (only successful traces) + _apiQueue.enqueueTrace( + latitude: position.latitude, + longitude: position.longitude, + repeaterId: targetId, + localSnr: result.localSnr, + localRssi: result.localRssi, + remoteSnr: result.remoteSnr, + timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000, + externalAntenna: getExternalAntenna?.call() ?? false, + noiseFloor: _pendingTxNoiseFloor, + ); + + // Update stats + _stats = _stats.copyWith(traceCount: _stats.traceCount + 1); + onStatsUpdated?.call(_stats); + + // Play receive sound for successful trace + _audioService?.playReceiveSound(); + } else { + debugLog('[TRACE] Trace failed: no response from $targetId'); + // Failed traces are NOT posted to API (local visual only) + } + + // Notify for noise floor graph and log updates + onTraceWindowComplete?.call(result); + + _scheduleNextTargetedPing(); + } + + /// Schedule next targeted ping after interval + void _scheduleNextTargetedPing() { + if (!_autoPingEnabled || !_targetedModeEnabled) { + debugLog('[TRACE] Not in targeted mode, not scheduling next trace'); + return; + } + + _targetedTimer?.cancel(); + _targetedTimer = Timer(Duration(milliseconds: _autoPingIntervalMs), () { + debugLog('[TRACE] Targeted ping timer fired'); + if (_autoPingEnabled && _targetedModeEnabled) { + if (_pingInProgress) { + debugLog('[TRACE] Ping already in progress, skipping'); + return; + } + _skipReason = null; + _sendTargetedPing(); + } + }); + + // Notify callback for countdown display + onAutoPingScheduled?.call(_autoPingIntervalMs, _skipReason); + + debugLog('[TRACE] Next targeted ping scheduled in ${_autoPingIntervalMs}ms'); + } + /// Stop any active TX echo tracking window /// Called when disabling auto mode to prevent late timer callbacks from /// triggering pings during cooldown (race condition fix) @@ -1253,6 +1527,7 @@ class PingService { _autoTimer?.cancel(); _autoTimer = null; _stopDiscoveryMode(); + _stopTargetedMode(); _wakelockService.dispose(); } } diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 70abdab..213f662 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -686,6 +686,11 @@ class _MapWidgetState extends State with TickerProviderStateMixin { markers: _buildDiscMarkers(appState.discLogEntries, appState.discDropEnabled), ), + // Trace markers (cyan/red circles for targeted ping results) + MarkerLayer( + markers: _buildTraceMarkers(appState.traceLogEntries), + ), + // Repeater markers (magenta with ID, rotate with map) MarkerLayer( rotate: true, @@ -1126,6 +1131,20 @@ class _MapWidgetState extends State with TickerProviderStateMixin { label: 'DISC', description: 'Location where you sent a discovery request but no repeater responded', ), + Divider(height: 1, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2)), + _buildLegendItem( + context: context, + color: Colors.cyan, + label: 'TRC', + description: 'Location where a trace reached the repeater', + ), + Divider(height: 1, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2)), + _buildLegendItem( + context: context, + color: Colors.red, + label: 'TRC', + description: 'Location where a trace got no response', + ), ], ), ), @@ -1599,6 +1618,284 @@ class _MapWidgetState extends State with TickerProviderStateMixin { }).toList(); } + List _buildTraceMarkers(List entries) { + return entries.map((entry) { + return Marker( + point: LatLng(entry.latitude, entry.longitude), + width: 20, + height: 20, + child: GestureDetector( + onTap: () => _showTraceDetails(entry), + child: Container( + decoration: BoxDecoration( + color: entry.success ? Colors.cyan : Colors.red, + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2), + boxShadow: const [ + BoxShadow( + color: Colors.black26, + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + ), + ), + ); + }).toList(); + } + + void _showTraceDetails(TraceLogEntry entry) { + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.75, + ), + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.fromLTRB(20, 24, 20, 32 + MediaQuery.of(context).viewPadding.bottom), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // Header with icon badge + Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.cyan.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.cyan.withValues(alpha: 0.4)), + ), + child: const Icon(Icons.gps_fixed, color: Colors.cyan, size: 24), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Trace', + style: Theme.of(context).textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + Text( + _formatTime(entry.timestamp), + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + const SizedBox(height: 20), + + // Location chip + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), + ), + child: Row( + children: [ + Icon(Icons.location_on, size: 16, color: Theme.of(context).colorScheme.onSurfaceVariant), + const SizedBox(width: 8), + Expanded( + child: Text( + '${entry.latitude.toStringAsFixed(5)}, ${entry.longitude.toStringAsFixed(5)}', + style: TextStyle( + fontSize: 13, + fontFamily: 'monospace', + color: Theme.of(context).colorScheme.onSurface, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Target repeater section header + Text( + entry.success + ? 'Target Repeater' + : 'No response from target repeater', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurfaceVariant, + letterSpacing: 0.5, + ), + ), + + if (entry.success) ...[ + const SizedBox(height: 12), + // Table with headers + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), + ), + child: Column( + children: [ + // Header row + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: Row( + children: [ + SizedBox( + width: _nodeColumnWidth(), + child: Text( + 'Node', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'RX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'RX RSSI', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + Expanded( + child: Text( + 'TX SNR', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + ], + ), + ), + Divider(height: 1, color: Theme.of(context).dividerColor), + // Data row + Builder(builder: (context) { + final localSnr = entry.localSnr ?? 0; + final localRssi = entry.localRssi ?? 0; + final remoteSnr = entry.remoteSnr ?? 0; + + Color rxSnrColor; + if (localSnr <= -1) { + rxSnrColor = Colors.red; + } else if (localSnr <= 5) { + rxSnrColor = Colors.orange; + } else { + rxSnrColor = Colors.green; + } + + Color rssiColor; + if (localRssi >= -70) { + rssiColor = Colors.green; + } else if (localRssi >= -100) { + rssiColor = Colors.orange; + } else { + rssiColor = Colors.red; + } + + Color txSnrColor; + if (remoteSnr <= -1) { + txSnrColor = Colors.red; + } else if (remoteSnr <= 5) { + txSnrColor = Colors.orange; + } else { + txSnrColor = Colors.green; + } + + return InkWell( + onTap: () => RepeaterIdChip.showRepeaterPopup(context, entry.targetRepeaterId), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 13, width: _nodeColumnWidth()), + // RX SNR + Expanded( + child: Center( + child: _buildStatChip( + value: localSnr.toStringAsFixed(1), + color: rxSnrColor, + ), + ), + ), + // RX RSSI + Expanded( + child: Center( + child: _buildStatChip( + value: '$localRssi', + color: rssiColor, + ), + ), + ), + // TX SNR + Expanded( + child: Center( + child: _buildStatChip( + value: remoteSnr.toStringAsFixed(1), + color: txSnrColor, + ), + ), + ), + ], + ), + ), + ); + }), + ], + ), + ), + ], + ], + ), + ), + ), + ), + ); + } + /// DISC marker color (#7B68EE - medium slate blue/purple) static const Color _discMarkerColor = Color(0xFF7B68EE); diff --git a/lib/widgets/noise_floor_chart.dart b/lib/widgets/noise_floor_chart.dart index 31ba933..d88357d 100644 --- a/lib/widgets/noise_floor_chart.dart +++ b/lib/widgets/noise_floor_chart.dart @@ -221,6 +221,8 @@ class InteractiveNoiseFloorChartState extends State PingEventType.rx => 'RX Received', PingEventType.discSuccess => 'Discovery Success', PingEventType.discFail => 'Discovery Failed', + PingEventType.traceSuccess => 'Trace Success', + PingEventType.traceFail => 'Trace Failed', }; final eventDescription = switch (marker.type) { @@ -229,6 +231,8 @@ class InteractiveNoiseFloorChartState extends State PingEventType.rx => 'Received passive observation', PingEventType.discSuccess => 'Discovery got response', PingEventType.discFail => 'Discovery got no response', + PingEventType.traceSuccess => 'Trace got response from target', + PingEventType.traceFail => 'Trace got no response from target', }; final hasLocation = marker.latitude != null && marker.longitude != null; @@ -845,10 +849,11 @@ class InteractiveNoiseFloorChartState extends State alignment: WrapAlignment.center, children: [ _legendItem(context, Colors.green, 'TX Success'), - _legendItem(context, Colors.red, 'TX Fail'), + _legendItem(context, Colors.red, 'TX/Trace Fail'), _legendItem(context, Colors.blue, 'RX'), _legendItem(context, Colors.purple, 'DISC Success'), _legendItem(context, Colors.grey, 'DISC Fail'), + _legendItem(context, Colors.cyan, 'Trace Success'), ], ); } diff --git a/lib/widgets/offline_mode_toggle.dart b/lib/widgets/offline_mode_toggle.dart new file mode 100644 index 0000000..c088ab4 --- /dev/null +++ b/lib/widgets/offline_mode_toggle.dart @@ -0,0 +1,198 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/app_state_provider.dart'; + +/// Shared offline mode toggle widget +/// Extracted from ping_controls.dart for use on both connection screen and ping controls +class OfflineModeToggle extends StatelessWidget { + const OfflineModeToggle({super.key}); + + /// Handle offline mode toggle with progress dialog when connected + static Future handleOfflineModeToggle( + BuildContext context, + AppStateProvider appState, + bool currentOfflineMode, + bool isConnected, + ) async { + final newMode = !currentOfflineMode; + + // If connected, show progress dialog during mode switch + if (isConnected) { + final statusText = newMode + ? 'Switching to offline mode...' + : 'Switching to online mode...'; + + // Show non-dismissible progress dialog + showDialog( + context: context, + barrierDismissible: false, + builder: (dialogContext) => PopScope( + canPop: false, + child: AlertDialog( + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + Text( + statusText, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 14), + ), + ], + ), + ), + ), + ); + + // Perform the mode switch + final result = await appState.setOfflineMode(newMode); + + // Close the progress dialog (check if context is still valid) + if (context.mounted) { + Navigator.of(context).pop(); + } + + // Show error dialog if switch failed + if (!result.success && context.mounted) { + showDialog( + context: context, + builder: (dialogContext) => AlertDialog( + title: const Text('Mode Switch Failed'), + content: Text( + result.error ?? 'An unknown error occurred', + style: const TextStyle(fontSize: 14), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(dialogContext).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } + } else { + // Not connected - simple toggle without dialog + await appState.setOfflineMode(newMode); + } + } + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + final isDark = Theme.of(context).brightness == Brightness.dark; + final appState = context.watch(); + final offlineMode = appState.offlineMode; + final offlinePingCount = appState.offlinePingCount; + final isConnected = appState.isConnected; + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () => handleOfflineModeToggle(context, appState, offlineMode, isConnected), + borderRadius: BorderRadius.circular(10), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), + decoration: BoxDecoration( + color: offlineMode + ? Colors.orange.withValues(alpha: 0.15) + : colorScheme.onSurface.withValues(alpha: 0.05), + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: offlineMode + ? Colors.orange.withValues(alpha: 0.4) + : colorScheme.outline.withValues(alpha: 0.2), + ), + ), + child: Row( + children: [ + // Icon + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: offlineMode + ? Colors.orange.withValues(alpha: 0.2) + : colorScheme.onSurface.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(6), + ), + child: Icon( + offlineMode ? Icons.cloud_off : Icons.cloud_queue, + size: 18, + color: offlineMode + ? (isDark ? Colors.orange.shade400 : Colors.orange.shade700) + : colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(width: 12), + // Label and count + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Offline Mode', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: offlineMode + ? (isDark ? Colors.orange.shade300 : Colors.orange.shade800) + : colorScheme.onSurface, + ), + ), + if (offlineMode && offlinePingCount > 0) + Text( + '$offlinePingCount pings saved locally', + style: TextStyle( + fontSize: 11, + color: isDark ? Colors.orange.shade400 : Colors.orange.shade600, + ), + ) + else + Text( + offlineMode + ? 'Data saved locally' + : 'Uploads immediately', + style: TextStyle( + fontSize: 11, + color: colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + // Toggle indicator + Container( + width: 44, + height: 26, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(13), + color: offlineMode + ? (isDark ? Colors.orange.shade600 : Colors.orange.shade500) + : (isDark ? const Color(0xFF475569) : const Color(0xFFCBD5E1)), + ), + child: AnimatedAlign( + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut, + alignment: offlineMode + ? Alignment.centerRight + : Alignment.centerLeft, + child: Container( + width: 22, + height: 22, + margin: const EdgeInsets.all(2), + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index ce7c670..436610f 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import '../providers/app_state_provider.dart'; import '../services/ping_service.dart'; import '../utils/debug_logger_io.dart'; +import 'offline_mode_toggle.dart'; /// Modern ping control panel with icon-based buttons and animated status class PingControls extends StatelessWidget { @@ -22,6 +23,7 @@ class PingControls extends StatelessWidget { final isPassiveModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.passive; final isHybridModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.hybrid; final isTxModeRunning = isActiveModeRunning || isHybridModeRunning; + final isTargetedRunning = appState.isTargetedModeRunning; final hybridEnabled = appState.preferences.hybridModeEnabled; final isPendingDisable = appState.isPendingDisable; // Disable pending, waiting for RX window to complete final cooldownActive = appState.cooldownTimer.isRunning; // Shared cooldown after disabling Active Mode @@ -108,7 +110,7 @@ class PingControls extends StatelessWidget { ? 'Cooldown ${cooldownRemaining}s' // After Active/Hybrid Mode disabled : 'Send Ping', color: const Color(0xFF0EA5E9), // sky-500 - enabled: canPingManual && !isTxModeRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && + enabled: canPingManual && !isTxModeRunning && !isTargetedRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && !rxWindowActive && !isPingSending && !discoveryWindowActive && !isPendingDisable, isActive: (isPingSending || rxWindowActive) && !isTxModeRunning, // Only active during manual ping flow onPressed: () => _sendPing(context, appState), @@ -157,7 +159,7 @@ class PingControls extends StatelessWidget { : isTxModeRunning ? const Color(0xFF22C55E) // green-500 : const Color(0xFF6366F1), // indigo-500 - enabled: !isPendingDisable && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed), + enabled: !isPendingDisable && !isTargetedRunning && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed), isActive: isPendingDisable || isTxModeRunning, onPressed: () => hybridEnabled ? _toggleHybridAuto(context, appState) : _toggleTxRxAuto(context, appState), showCooldown: false, @@ -191,7 +193,7 @@ class PingControls extends StatelessWidget { color: isPassiveModeRunning ? const Color(0xFF22C55E) // green-500 : const Color(0xFF6366F1), // indigo-500 - enabled: isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isPendingDisable && + enabled: isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isTargetedRunning && !isPendingDisable && !isPingSending && !rxWindowActive && !cooldownActive && prefs.externalAntennaSet && isPowerSet), isActive: isPassiveModeRunning && (discoveryWindowActive || autoPingWaiting), // Active during listening/waiting phases @@ -224,15 +226,11 @@ class PingControls extends StatelessWidget { else const SizedBox(height: 8), - // Offline Mode and Sound toggles row - const Row( - children: [ - // Offline Mode toggle (expanded) - Expanded(child: _OfflineModeToggle()), - SizedBox(width: 8), - // Sound toggle (compact, right side) - _SoundToggle(), - ], + // Targeted Ping controls + _TargetedPingSection( + isAnyModeRunning: isActiveModeRunning || isPassiveModeRunning || isHybridModeRunning, + cooldownActive: cooldownActive, + cooldownRemaining: cooldownRemaining, ), ], ); @@ -445,370 +443,199 @@ class _ActionButtonState extends State<_ActionButton> } } -/// Compact sound notification toggle - matches height of _OfflineModeToggle -class _SoundToggle extends StatelessWidget { - const _SoundToggle(); +/// Targeted Ping controls - hex text field + start/stop button +class _TargetedPingSection extends StatefulWidget { + final bool isAnyModeRunning; + final bool cooldownActive; + final int cooldownRemaining; - @override - Widget build(BuildContext context) { - final appState = context.watch(); - final soundEnabled = appState.isSoundEnabled; - final colorScheme = Theme.of(context).colorScheme; - final isDark = Theme.of(context).brightness == Brightness.dark; + const _TargetedPingSection({ + required this.isAnyModeRunning, + required this.cooldownActive, + required this.cooldownRemaining, + }); - return Material( - color: Colors.transparent, - child: InkWell( - onTap: () => appState.toggleSoundEnabled(), - borderRadius: BorderRadius.circular(10), - child: Container( - // Match _OfflineModeToggle: padding 10v + icon container (6+18+6) + text adds more height - // _OfflineModeToggle content: icon 30px, text column ~34px, toggle 26px - // Use same padding and let IntrinsicHeight from Row handle matching - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), - decoration: BoxDecoration( - color: soundEnabled - ? Colors.blue.withValues(alpha: 0.15) - : colorScheme.onSurface.withValues(alpha: 0.05), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: soundEnabled - ? Colors.blue.withValues(alpha: 0.4) - : colorScheme.outline.withValues(alpha: 0.2), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: soundEnabled - ? Colors.blue.withValues(alpha: 0.2) - : colorScheme.onSurface.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(6), - ), - child: Icon( - soundEnabled ? Icons.volume_up : Icons.volume_off, - size: 18, - color: soundEnabled - ? (isDark ? Colors.blue.shade400 : Colors.blue.shade700) - : colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 8), - // Add text column to match offline mode toggle height - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Sound', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: soundEnabled - ? (isDark ? Colors.blue.shade300 : Colors.blue.shade800) - : colorScheme.onSurface, - ), - ), - Text( - soundEnabled ? 'On' : 'Off', - style: TextStyle( - fontSize: 11, - color: soundEnabled - ? (isDark ? Colors.blue.shade400 : Colors.blue.shade600) - : colorScheme.onSurfaceVariant, - ), - ), - ], - ), - ], - ), - ), - ), - ); - } + @override + State<_TargetedPingSection> createState() => _TargetedPingSectionState(); } -/// Compact offline mode toggle matching app design language -class _OfflineModeToggle extends StatelessWidget { - const _OfflineModeToggle(); - - // Offline mode is now enabled - static const bool _isEnabled = true; - - /// Handle offline mode toggle with progress dialog when connected - static Future _handleOfflineModeToggle( - BuildContext context, - AppStateProvider appState, - bool currentOfflineMode, - bool isConnected, - ) async { - final newMode = !currentOfflineMode; - - // If connected, show progress dialog during mode switch - if (isConnected) { - final statusText = newMode - ? 'Switching to offline mode...' - : 'Switching to online mode...'; - - // Show non-dismissible progress dialog - showDialog( - context: context, - barrierDismissible: false, - builder: (dialogContext) => PopScope( - canPop: false, - child: AlertDialog( - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const CircularProgressIndicator(), - const SizedBox(height: 16), - Text( - statusText, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 14), - ), - ], - ), - ), - ), - ); +class _TargetedPingSectionState extends State<_TargetedPingSection> { + final _controller = TextEditingController(); + bool _isStarting = false; - // Perform the mode switch - final result = await appState.setOfflineMode(newMode); - - // Close the progress dialog (check if context is still valid) - if (context.mounted) { - Navigator.of(context).pop(); + @override + void initState() { + super.initState(); + // Restore any previously set target ID + WidgetsBinding.instance.addPostFrameCallback((_) { + final appState = context.read(); + final existing = appState.targetRepeaterId; + if (existing != null && existing.isNotEmpty && _controller.text != existing) { + _controller.text = existing; } + }); + } - // Show error dialog if switch failed - if (!result.success && context.mounted) { - showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: const Text('Mode Switch Failed'), - content: Text( - result.error ?? 'An unknown error occurred', - style: const TextStyle(fontSize: 14), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(dialogContext).pop(), - child: const Text('OK'), - ), - ], - ), - ); - } - } else { - // Not connected - simple toggle without dialog - await appState.setOfflineMode(newMode); - } + @override + void dispose() { + _controller.dispose(); + super.dispose(); } @override Widget build(BuildContext context) { + final appState = context.watch(); + final isTargetedRunning = appState.isTargetedModeRunning; + final maxLen = appState.effectiveHopBytes * 2; final colorScheme = Theme.of(context).colorScheme; - final isDark = Theme.of(context).brightness == Brightness.dark; - // When disabled, always show as "off" state - if (!_isEnabled) { - return Opacity( - opacity: 0.5, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), - decoration: BoxDecoration( - color: colorScheme.onSurface.withValues(alpha: 0.05), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: colorScheme.outline.withValues(alpha: 0.2), - ), - ), - child: Row( - children: [ - // Icon - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: colorScheme.onSurface.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(6), - ), - child: Icon( - Icons.cloud_queue, - size: 18, - color: colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 12), - // Label and "Coming soon" - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Offline Mode', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: colorScheme.onSurfaceVariant, - ), - ), - Text( - 'Coming soon', - style: TextStyle( - fontSize: 11, - fontStyle: FontStyle.italic, - color: colorScheme.onSurfaceVariant, - ), - ), - ], - ), - ), - // Toggle indicator (always off) - Container( - width: 44, - height: 26, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - color: isDark ? const Color(0xFF475569) : const Color(0xFFCBD5E1), // slate-600/300 - ), - child: Align( - alignment: Alignment.centerLeft, - child: Container( - width: 22, - height: 22, - margin: const EdgeInsets.all(2), - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - ), - ), - ), - ), - ], - ), - ), - ); + // Determine if the start button should be enabled + final hexText = _controller.text.trim(); + final isValidHex = hexText.isNotEmpty && + hexText.length == maxLen && + RegExp(r'^[0-9a-fA-F]+$').hasMatch(hexText); + final canStart = isValidHex && + !widget.isAnyModeRunning && + !isTargetedRunning && + !widget.cooldownActive && + appState.isConnected; + + // Status text for when targeted mode is running + String? statusText; + if (isTargetedRunning) { + final discoveryWindowActive = appState.discoveryWindowTimer.isRunning; + final discoveryRemaining = appState.discoveryWindowTimer.remainingSec; + final autoPingWaiting = appState.autoPingTimer.isRunning; + final autoPingRemaining = appState.autoPingTimer.remainingSec; + + if (discoveryWindowActive) { + statusText = 'Listening ${discoveryRemaining}s'; + } else if (autoPingWaiting) { + statusText = 'Next in ${autoPingRemaining}s'; + } } - // Original implementation when enabled - final appState = context.watch(); - final offlineMode = appState.offlineMode; - final offlinePingCount = appState.offlinePingCount; - final isConnected = appState.isConnected; + final isEnabled = (canStart || isTargetedRunning) && !_isStarting; + final buttonColor = (isTargetedRunning || _isStarting) + ? const Color(0xFF22C55E) // green-500 when running/starting + : Colors.cyan; + final effectiveColor = isEnabled ? buttonColor : colorScheme.onSurfaceVariant; - return Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _handleOfflineModeToggle(context, appState, offlineMode, isConnected), + return Container( + decoration: BoxDecoration( + color: effectiveColor.withValues(alpha: isTargetedRunning ? 0.15 : 0.08), borderRadius: BorderRadius.circular(10), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), - decoration: BoxDecoration( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.15) - : colorScheme.onSurface.withValues(alpha: 0.05), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.4) - : colorScheme.outline.withValues(alpha: 0.2), - ), - ), - child: Row( - children: [ - // Icon - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.2) - : colorScheme.onSurface.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(6), - ), - child: Icon( - offlineMode ? Icons.cloud_off : Icons.cloud_queue, - size: 18, - color: offlineMode - ? (isDark ? Colors.orange.shade400 : Colors.orange.shade700) - : colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 12), - // Label and count - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Offline Mode', + border: Border.all( + color: effectiveColor.withValues(alpha: isTargetedRunning ? 0.5 : 0.25), + width: isTargetedRunning ? 1.5 : 1, + ), + ), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: Row( + children: [ + // Targeted button + Expanded( + child: GestureDetector( + onTap: isEnabled + ? () async { + HapticFeedback.lightImpact(); + if (!isTargetedRunning) { + setState(() => _isStarting = true); + appState.setTargetRepeaterId(_controller.text.trim().toUpperCase()); + } + await appState.toggleAutoPing(AutoMode.targeted); + if (mounted) setState(() => _isStarting = false); + } + : null, + behavior: HitTestBehavior.opaque, + child: Row( + children: [ + Icon( + Icons.gps_fixed, + size: 18, + color: effectiveColor, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + _isStarting + ? 'Starting...' + : isTargetedRunning + ? (statusText ?? 'Stop') + : widget.cooldownActive + ? 'Cooldown ${widget.cooldownRemaining}s' + : 'Trace Mode', style: TextStyle( fontSize: 13, - fontWeight: FontWeight.w500, - color: offlineMode - ? (isDark ? Colors.orange.shade300 : Colors.orange.shade800) - : colorScheme.onSurface, + fontWeight: isTargetedRunning ? FontWeight.w600 : FontWeight.w500, + color: isEnabled ? colorScheme.onSurface : colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), + overflow: TextOverflow.ellipsis, ), - if (offlineMode && offlinePingCount > 0) - Text( - '$offlinePingCount pings saved locally', - style: TextStyle( - fontSize: 11, - color: isDark ? Colors.orange.shade400 : Colors.orange.shade600, - ), - ) - else - Text( - offlineMode - ? 'Data saved locally' - : 'Uploads immediately', - style: TextStyle( - fontSize: 11, - color: colorScheme.onSurfaceVariant, - ), - ), - ], - ), + ), + ], ), - // Toggle indicator - Container( - width: 44, - height: 26, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - color: offlineMode - ? (isDark ? Colors.orange.shade600 : Colors.orange.shade500) - : (isDark ? const Color(0xFF475569) : const Color(0xFFCBD5E1)), // slate-600/300 + ), + ), + const SizedBox(width: 8), + // Hex text field + SizedBox( + width: 80, + child: TextField( + controller: _controller, + enabled: !isTargetedRunning, + maxLength: maxLen, + textCapitalization: TextCapitalization.characters, + style: TextStyle( + fontSize: 14, + fontFamily: 'monospace', + color: isTargetedRunning + ? colorScheme.onSurfaceVariant + : colorScheme.onSurface, + ), + decoration: InputDecoration( + hintText: 'e.g. ${maxLen == 2 ? '4E' : maxLen == 4 ? '4E7A' : '4E7A3B'}', + hintStyle: TextStyle( + fontSize: 12, + color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), - child: AnimatedAlign( - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut, - alignment: offlineMode - ? Alignment.centerRight - : Alignment.centerLeft, - child: Container( - width: 22, - height: 22, - margin: const EdgeInsets.all(2), - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - ), - ), + counterText: '', + isDense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), ), ), - ], + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[0-9a-fA-F]')), + _UpperCaseTextFormatter(), + ], + onChanged: (value) { + appState.setTargetRepeaterId(value.trim().toUpperCase()); + setState(() {}); + }, + ), ), - ), + ], ), ); } } +/// Text formatter that converts input to uppercase +class _UpperCaseTextFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, + TextEditingValue newValue, + ) { + return TextEditingValue( + text: newValue.text.toUpperCase(), + selection: newValue.selection, + ); + } +} + /// Compact ping controls for minimized panel view /// Shows 3 small horizontal pill buttons in a row /// Active button expands to show context (e.g., "Listening 5s") @@ -820,7 +647,7 @@ class CompactPingControls extends StatefulWidget { } /// Tracks which button should stay expanded during cooldown -enum _LastActiveButton { none, sendPing, activeMode, passiveMode } +enum _LastActiveButton { none, sendPing, activeMode, passiveMode, targeted } class _CompactPingControlsState extends State { // Static so it persists across widget rebuilds (e.g., expand/minimize panel) @@ -837,6 +664,7 @@ class _CompactPingControlsState extends State { final isPassiveModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.passive; final isHybridModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.hybrid; final isTxModeRunning = isActiveModeRunning || isHybridModeRunning; + final isTargetedRunning = appState.isTargetedModeRunning; final hybridEnabled = appState.preferences.hybridModeEnabled; final isPendingDisable = appState.isPendingDisable; final cooldownActive = appState.cooldownTimer.isRunning; @@ -873,9 +701,11 @@ class _CompactPingControlsState extends State { _lastActiveButton = _LastActiveButton.activeMode; } else if (passiveModeCurrentlyActive) { _lastActiveButton = _LastActiveButton.passiveMode; + } else if (isTargetedRunning) { + _lastActiveButton = _LastActiveButton.targeted; } // Reset when no cooldown and no activity - if (!cooldownActive && !manualCooldownActive && !sendPingCurrentlyActive && !activeModeCurrentlyActive && !passiveModeCurrentlyActive) { + if (!cooldownActive && !manualCooldownActive && !sendPingCurrentlyActive && !activeModeCurrentlyActive && !passiveModeCurrentlyActive && !isTargetedRunning) { _lastActiveButton = _LastActiveButton.none; } @@ -890,25 +720,36 @@ class _CompactPingControlsState extends State { (cooldownActive && _lastActiveButton == _LastActiveButton.passiveMode); // Determine which buttons are colored (enabled or active) - final sendPingEnabled = canPingManual && !isTxModeRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && + final sendPingEnabled = canPingManual && !isTxModeRunning && !isTargetedRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && !rxWindowActive && !isPingSending && !discoveryWindowActive && !isPendingDisable; final sendPingActive = (isPingSending || rxWindowActive) && !isTxModeRunning && !cooldownActive && !manualCooldownActive; final sendPingShowColor = sendPingEnabled || sendPingActive; - final activeModeEnabled = !isPendingDisable && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed); + final activeModeEnabled = !isPendingDisable && !isTargetedRunning && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed); final activeModeActive = isPendingDisable || isTxModeRunning; final activeModeShowColor = activeModeEnabled || activeModeActive; - final passiveModeEnabled = isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isPendingDisable && + final passiveModeEnabled = isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isTargetedRunning && !isPendingDisable && !isPingSending && !rxWindowActive && !cooldownActive && prefs.externalAntennaSet && isPowerSet); final passiveModeActive = isPassiveModeRunning && (discoveryWindowActive || autoPingWaiting); final passiveModeShowColor = passiveModeEnabled || passiveModeActive; + // Trace Mode (only relevant when a repeater ID has been entered) + final hasTargetRepeaterId = appState.targetRepeaterId != null && appState.targetRepeaterId!.isNotEmpty; + final targetedCurrentlyActive = isTargetedRunning; + final traceModeExpanded = targetedCurrentlyActive || + (cooldownActive && _lastActiveButton == _LastActiveButton.targeted); + final traceModeEnabled = hasTargetRepeaterId && !isTxModeRunning && !isPassiveModeRunning && + !isPendingDisable && !isPingSending && !rxWindowActive && !cooldownActive && + !manualCooldownActive && appState.isConnected && prefs.externalAntennaSet && isPowerSet; + final traceModeActive = isTargetedRunning; + final traceModeShowColor = traceModeEnabled || traceModeActive; + // Check if any button is actively expanded (showing label) - final anyExpanded = sendPingExpanded || activeModeExpanded || passiveModeExpanded; + final anyExpanded = sendPingExpanded || activeModeExpanded || passiveModeExpanded || traceModeExpanded; // Check if all buttons are disabled (no color) - used to split space equally in initial state - final allDisabled = !sendPingShowColor && !activeModeShowColor && !passiveModeShowColor; + final allDisabled = !sendPingShowColor && !activeModeShowColor && !passiveModeShowColor && (!hasTargetRepeaterId || !traceModeShowColor); // Build the buttons final sendPingButton = _CompactActionButton( @@ -1003,6 +844,39 @@ class _CompactPingControlsState extends State { onPressed: () => _toggleRxAuto(context, appState), ); + // Build trace mode button (only used when hasTargetRepeaterId) + final traceModeButton = _CompactActionButton( + icon: Icons.gps_fixed, + label: _getTraceModeLabel( + isTargetedRunning: isTargetedRunning, + discoveryWindowActive: discoveryWindowActive, + discoveryWindowRemaining: discoveryWindowRemaining, + autoPingWaiting: autoPingWaiting, + autoPingRemaining: autoPingRemaining, + showFullText: traceModeExpanded, + cooldownActive: cooldownActive, + cooldownRemaining: cooldownRemaining, + isExpandedDuringCooldown: traceModeExpanded && cooldownActive, + ), + color: isTargetedRunning + ? const Color(0xFF22C55E) // green-500 + : const Color(0xFF06B6D4), // cyan-500 + enabled: traceModeEnabled || isTargetedRunning, + isActive: traceModeActive, + isExpanded: traceModeExpanded, + progress: discoveryWindowActive && isTargetedRunning + ? appState.discoveryWindowTimer.progress + : autoPingWaiting && isTargetedRunning + ? appState.autoPingTimer.progress + : cooldownActive && _lastActiveButton == _LastActiveButton.targeted + ? appState.cooldownTimer.progress + : null, + onPressed: () { + HapticFeedback.lightImpact(); + appState.toggleAutoPing(AutoMode.targeted); + }, + ); + // Layout logic: // - If button is expanded (including during cooldown): stays big // - If no button is expanded: all colored buttons share space equally @@ -1034,6 +908,17 @@ class _CompactPingControlsState extends State { Expanded(child: passiveModeButton) else passiveModeButton, + + // Trace Mode (only shown when a repeater ID has been entered) + if (hasTargetRepeaterId) ...[ + const SizedBox(width: 6), + if (traceModeExpanded) + Expanded(child: traceModeButton) + else if (!anyExpanded && (traceModeShowColor || allDisabled)) + Expanded(child: traceModeButton) + else + traceModeButton, + ], ], ); } @@ -1119,6 +1004,31 @@ class _CompactPingControlsState extends State { return null; } + /// Get label for Trace Mode button + /// When showFullText is true: "Listening 5s", when false: "5s" + String? _getTraceModeLabel({ + required bool isTargetedRunning, + required bool discoveryWindowActive, + required int discoveryWindowRemaining, + required bool autoPingWaiting, + required int autoPingRemaining, + required bool showFullText, + required bool cooldownActive, + required int cooldownRemaining, + required bool isExpandedDuringCooldown, + }) { + if (isTargetedRunning) { + if (discoveryWindowActive) return showFullText ? 'Listening ${discoveryWindowRemaining}s' : '${discoveryWindowRemaining}s'; + if (autoPingWaiting) return showFullText ? 'Next in ${autoPingRemaining}s' : '${autoPingRemaining}s'; + return showFullText ? 'Stop' : null; + } + // Show cooldown if this button caused it + if (cooldownActive && isExpandedDuringCooldown) { + return showFullText ? 'Cooldown ${cooldownRemaining}s' : '${cooldownRemaining}s'; + } + return null; + } + Future _sendPing(BuildContext context, AppStateProvider appState) async { HapticFeedback.mediumImpact(); @@ -1163,6 +1073,7 @@ class LandscapePingControls extends StatelessWidget { final isPassiveModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.passive; final isHybridModeRunning = appState.autoPingEnabled && appState.autoMode == AutoMode.hybrid; final isTxModeRunning = isActiveModeRunning || isHybridModeRunning; + final isTargetedRunning = appState.isTargetedModeRunning; final hybridEnabled = appState.preferences.hybridModeEnabled; final isPendingDisable = appState.isPendingDisable; final cooldownActive = appState.cooldownTimer.isRunning; @@ -1213,7 +1124,7 @@ class LandscapePingControls extends StatelessWidget { icon: Icons.cell_tower, tooltip: txNotAllowed ? 'Zone Full (Passive Only)' : 'Send Ping', color: const Color(0xFF0EA5E9), // sky-500 - enabled: canPingManual && !isTxModeRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && + enabled: canPingManual && !isTxModeRunning && !isTargetedRunning && !cooldownActive && !manualCooldownActive && !txBlockedByOffline && !txNotAllowed && !rxWindowActive && !isPingSending && !discoveryWindowActive && !isPendingDisable, isActive: (isPingSending || rxWindowActive) && !isTxModeRunning, countdown: isPingSending @@ -1242,7 +1153,7 @@ class LandscapePingControls extends StatelessWidget { : isTxModeRunning ? const Color(0xFF22C55E) // green-500 : const Color(0xFF6366F1), // indigo-500 - enabled: !isPendingDisable && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed), + enabled: !isPendingDisable && !isTargetedRunning && ((isTxModeRunning || (canStartAuto && !isPassiveModeRunning && !cooldownActive && !isPingSending && !rxWindowActive)) && !txBlockedByOffline && !txNotAllowed), isActive: isPendingDisable || isTxModeRunning, countdown: isTxModeRunning ? (discoveryWindowActive @@ -1268,7 +1179,7 @@ class LandscapePingControls extends StatelessWidget { color: isPassiveModeRunning ? const Color(0xFF22C55E) // green-500 : const Color(0xFF6366F1), // indigo-500 - enabled: isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isPendingDisable && + enabled: isPassiveModeRunning || (appState.isConnected && !isTxModeRunning && !isTargetedRunning && !isPendingDisable && !isPingSending && !rxWindowActive && !cooldownActive && prefs.externalAntennaSet && isPowerSet), isActive: isPassiveModeRunning && (discoveryWindowActive || autoPingWaiting), @@ -1295,7 +1206,7 @@ class LandscapePingControls extends StatelessWidget { label: 'Offline', isOn: offlineMode, color: Colors.orange, - onTap: () => _OfflineModeToggle._handleOfflineModeToggle( + onTap: () => OfflineModeToggle.handleOfflineModeToggle( context, appState, offlineMode, From 60f41eac718006560c4fd0db50bf992a08fda978 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 13:54:01 -0400 Subject: [PATCH 39/57] - Fixed a regression where device firmware version was no longer being parsed correctly --- lib/providers/app_state_provider.dart | 4 +++ lib/screens/connection_screen.dart | 36 +++++++++++++++++---------- lib/services/meshcore/connection.dart | 9 +++++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index af7c317..7be9c97 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -120,6 +120,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Device info DeviceModel? _deviceModel; String? _manufacturerString; + String? _firmwareVersionString; String? _devicePublicKey; String? _offlineContactUri; @@ -303,6 +304,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ({double lat, double lon})? get lastKnownPosition => _lastKnownPosition; DeviceModel? get deviceModel => _deviceModel; String? get manufacturerString => _manufacturerString; + String? get firmwareVersionString => _firmwareVersionString; String? get devicePublicKey => _devicePublicKey; PingStats get pingStats => _pingStats; bool get autoPingEnabled => _autoPingEnabled; @@ -1030,6 +1032,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (step == ConnectionStep.connected) { // Update device info _manufacturerString = _meshCoreConnection!.deviceInfo?.manufacturer; + _firmwareVersionString = _meshCoreConnection!.deviceInfo?.firmwareVersionString; _deviceModel = _meshCoreConnection!.deviceModel; _devicePublicKey = _meshCoreConnection!.devicePublicKey; debugLog('[APP] Device public key stored: ${_devicePublicKey?.substring(0, 16) ?? 'null'}...'); @@ -2333,6 +2336,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _connectionStep = ConnectionStep.disconnected; _deviceModel = null; _manufacturerString = null; + _firmwareVersionString = null; _devicePublicKey = null; _offlineContactUri = null; _displayDeviceName = null; diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index c0581d6..37aea5b 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -258,24 +258,34 @@ class _ConnectionScreenState extends State with WidgetsBinding // Get device name - uses displayDeviceName which prefers SelfInfo name over BLE advertisement name final deviceName = appState.displayDeviceName ?? 'Unknown'; - // Parse version from manufacturer string and use shortName from device model for hardware - // Format examples: - // - "MeshCore (Heltec V3) v1.10.0" - // - "Ikoka Stick-E22-30dBm (Xiao_nrf52) nightly-e31c46f" + // Extract version from firmware version string (v7+), fall back to manufacturer string + // Supports: "v1.14.0-9f1a3ea" → "1.14.0", "nightly-9f1a3ea" → "nightly-9f1a3ea" String? version; - final manufacturerString = appState.manufacturerString; - if (manufacturerString != null) { - // Use regex to find version pattern directly instead of splitting - // Match: v followed by digits/dots, OR nightly- followed by hex, OR just digits.digits - final versionRegex = RegExp(r'(v[\d.]+|nightly-[a-f0-9]+|\d+\.\d+\.\d+)'); - final match = versionRegex.firstMatch(manufacturerString); - if (match != null) { - version = match.group(1); + final fwString = appState.firmwareVersionString; + if (fwString != null && fwString.isNotEmpty) { + final semverMatch = RegExp(r'(\d+\.\d+\.\d+)').firstMatch(fwString); + if (semverMatch != null) { + version = semverMatch.group(1); + } else { + final nightlyMatch = RegExp(r'(nightly-[a-f0-9]+)').firstMatch(fwString); + if (nightlyMatch != null) { + version = nightlyMatch.group(1); + } + } + } + if (version == null) { + final manufacturerString = appState.manufacturerString; + if (manufacturerString != null) { + final versionRegex = RegExp(r'(v[\d.]+|nightly-[a-f0-9]+|\d+\.\d+\.\d+)'); + final match = versionRegex.firstMatch(manufacturerString); + if (match != null) { + version = match.group(1); + } } } // Use shortName from device model if available, otherwise fall back to manufacturer string - final hardware = appState.deviceModel?.shortName ?? manufacturerString ?? 'Unknown'; + final hardware = appState.deviceModel?.shortName ?? appState.manufacturerString ?? 'Unknown'; final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index f3fdaca..fa97a16 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -17,12 +17,14 @@ class DeviceQueryResponse { final int protocolVersion; final String manufacturer; final String? firmwareBuildDate; // Added in protocol v8 + final String? firmwareVersionString; // e.g. "v1.14.0-9f1a3ea" (v7+, 20-byte C-string) final int? pathHashMode; // 0=1-byte, 1=2-byte, 2=3-byte (null if old firmware, v10+) const DeviceQueryResponse({ required this.protocolVersion, required this.manufacturer, this.firmwareBuildDate, + this.firmwareVersionString, this.pathHashMode, }); } @@ -454,10 +456,12 @@ class MeshCoreConnection { // Parse additional fields from v9+ firmware int? pathHashMode; + String? firmwareVersionString; if (reader.remainingBytesCount > 0) { - // FIRMWARE_VERSION: 20 bytes (skip) + // FIRMWARE_VERSION: 20-byte null-terminated C-string if (reader.remainingBytesCount >= 20) { - reader.readBytes(20); // firmware version string + firmwareVersionString = reader.readCString(20); + debugLog('[CONN] Firmware version string: $firmwareVersionString'); } // client_repeat: 1 byte (v9+, skip) @@ -479,6 +483,7 @@ class MeshCoreConnection { protocolVersion: firmwareVer, manufacturer: manufacturerModel, firmwareBuildDate: buildDate, + firmwareVersionString: firmwareVersionString, pathHashMode: pathHashMode, ); From 30216910cace3b04977df727b4ad0aab40972434 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 14:48:34 -0400 Subject: [PATCH 40/57] - Redesigned the Connection tab for clarity. The previous layout was getting cluttered and hard to navigate. - Offline data session management is now always visible under Settings. --- lib/screens/connection_screen.dart | 988 ++++++++++++-------------- lib/screens/settings_screen.dart | 17 +- lib/widgets/offline_mode_toggle.dart | 165 ++--- lib/widgets/regional_config_card.dart | 102 ++- 4 files changed, 640 insertions(+), 632 deletions(-) diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index 37aea5b..edc35d4 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -75,58 +75,6 @@ class _ConnectionScreenState extends State with WidgetsBinding @override Widget build(BuildContext context) { final appState = context.watch(); - final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; - - // Build FAB for scanning - show Cancel during scan, Scan when idle - // Hide FAB entirely during maintenance mode (maintenance UI has its own buttons) - // Hide FAB when Bluetooth is off (shows full-screen message instead) - // Hide FAB during auto-reconnect - Widget? fab; - if (appState.isScanning) { - // Show Cancel FAB during active scan - fab = isLandscape - ? FloatingActionButton.small( - onPressed: () => appState.stopScan(), - backgroundColor: Colors.red, - child: const Icon(Icons.close), - ) - : FloatingActionButton.extended( - onPressed: () => appState.stopScan(), - icon: const Icon(Icons.close), - label: const Text('Cancel'), - backgroundColor: Colors.red, - ); - } else if (appState.connectionStep == ConnectionStep.disconnected && - !appState.isAutoReconnecting && - (!appState.maintenanceMode || appState.offlineMode) && - !appState.isBluetoothOff) { - // Offline mode bypasses both zone and maintenance checks - final canScan = appState.offlineMode || appState.inZone == true; - fab = isLandscape - ? FloatingActionButton.small( - onPressed: canScan ? () => appState.startScan() : null, - backgroundColor: canScan ? null : Colors.grey, - child: const Icon(Icons.bluetooth_searching), - ) - : FloatingActionButton.extended( - onPressed: canScan ? () => appState.startScan() : null, - icon: const Icon(Icons.bluetooth_searching), - label: Text(appState.offlineMode - ? 'Scan' - : appState.gpsStatus == GpsStatus.disabled - ? 'GPS Disabled' - : appState.gpsStatus == GpsStatus.permissionDenied - ? 'GPS Required' - : appState.isCheckingZone - ? 'Checking Zone...' - : appState.inZone == true - ? 'Scan' - : appState.inZone == false - ? 'Outside Zone' - : 'Checking Zone...'), - backgroundColor: canScan ? null : Colors.grey, - ); - } return Scaffold( appBar: AppBar( @@ -134,26 +82,34 @@ class _ConnectionScreenState extends State with WidgetsBinding automaticallyImplyLeading: false, ), body: _buildBody(context, appState), - floatingActionButton: fab, ); } Widget _buildBody(BuildContext context, AppStateProvider appState) { - // Show reconnecting UI + // Reconnecting and connection progress don't show the zone bar or bottom bar if (appState.connectionStep == ConnectionStep.reconnecting) { return _buildReconnectingView(context, appState); } - - // Show connection progress if (appState.connectionStep != ConnectionStep.disconnected && appState.connectionStep != ConnectionStep.connected && appState.connectionStep != ConnectionStep.error) { return _buildConnectionProgress(context, appState); } + // All other states: zone bar top, content middle, action bar bottom + return Column( + children: [ + _buildZoneStatusBar(context, appState), + Expanded(child: _buildStateContent(context, appState)), + _buildBottomBar(context, appState), + ], + ); + } + + /// Routes to the correct sub-view (zone bar is already rendered above) + Widget _buildStateContent(BuildContext context, AppStateProvider appState) { // Show connected state if (appState.isConnected) { - // Show path hash mode warning popup if pending final pathWarning = appState.pendingPathHashWarning; if (pathWarning != null) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -174,6 +130,99 @@ class _ConnectionScreenState extends State with WidgetsBinding return _buildDeviceList(context, appState); } + /// Persistent bottom action bar: offline toggle + scan/cancel/disconnect + Widget _buildBottomBar(BuildContext context, AppStateProvider appState) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 16), + child: Row( + children: [ + const Expanded(child: OfflineModeToggle()), + const SizedBox(width: 12), + Expanded(child: _buildActionButton(context, appState)), + ], + ), + ); + } + + /// The right-side action button: Scan, Cancel, or Disconnect + Widget _buildActionButton(BuildContext context, AppStateProvider appState) { + if (appState.isConnected) { + // Disconnect + return _buildBottomButton( + icon: Icons.bluetooth_disabled, + label: 'Disconnect', + color: Colors.red, + onPressed: () async => await appState.disconnect(), + ); + } + + if (appState.isScanning) { + // Cancel scan + return _buildBottomButton( + icon: Icons.close, + label: 'Cancel', + color: Colors.red, + onPressed: () => appState.stopScan(), + ); + } + + // Scan — disabled when can't scan + final canScan = appState.connectionStep == ConnectionStep.disconnected && + !appState.isAutoReconnecting && + (!appState.maintenanceMode || appState.offlineMode) && + !appState.isBluetoothOff && + (appState.offlineMode || appState.inZone == true); + + return _buildBottomButton( + icon: Icons.bluetooth_searching, + label: 'Scan', + color: Theme.of(context).colorScheme.primary, + onPressed: canScan ? () => appState.startScan() : null, + ); + } + + /// Styled button matching OfflineModeToggle shape + Widget _buildBottomButton({ + required IconData icon, + required String label, + required Color color, + VoidCallback? onPressed, + }) { + final enabled = onPressed != null; + final effectiveColor = enabled ? color : Colors.grey; + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onPressed, + borderRadius: BorderRadius.circular(10), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: effectiveColor.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: effectiveColor.withValues(alpha: 0.4)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(icon, size: 18, color: effectiveColor), + const SizedBox(width: 8), + Text( + label, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: effectiveColor, + ), + ), + ], + ), + ), + ), + ); + } + Widget _buildConnectionProgress(BuildContext context, AppStateProvider appState) { final step = appState.connectionStep; final totalSteps = ConnectionStepExtension.totalSteps; @@ -259,7 +308,6 @@ class _ConnectionScreenState extends State with WidgetsBinding final deviceName = appState.displayDeviceName ?? 'Unknown'; // Extract version from firmware version string (v7+), fall back to manufacturer string - // Supports: "v1.14.0-9f1a3ea" → "1.14.0", "nightly-9f1a3ea" → "nightly-9f1a3ea" String? version; final fwString = appState.firmwareVersionString; if (fwString != null && fwString.isNotEmpty) { @@ -284,117 +332,104 @@ class _ConnectionScreenState extends State with WidgetsBinding } } - // Use shortName from device model if available, otherwise fall back to manufacturer string final hardware = appState.deviceModel?.shortName ?? appState.manufacturerString ?? 'Unknown'; - + final platform = appState.deviceModel?.platform; final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; + final prefs = appState.preferences; + final isAutoMode = appState.autoPingEnabled; + final isPowerSet = prefs.autoPowerSet || prefs.powerLevelSet || appState.deviceModel != null; - // Build device info card - final deviceInfoCard = Card( + // Compact device summary card + final deviceSummaryCard = Card( child: Padding( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ + // Header: BT icon + name/status Row( children: [ - const Icon( - Icons.bluetooth_connected, - color: Colors.green, - size: 28, - ), - const SizedBox(width: 12), + const Icon(Icons.bluetooth_connected, color: Colors.green, size: 20), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Connected', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Colors.green, - fontWeight: FontWeight.bold, - ), + deviceName, + style: Theme.of(context).textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.bold, + ), + overflow: TextOverflow.ellipsis, ), Text( - deviceName, - style: Theme.of(context).textTheme.bodyLarge, + 'Connected', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.green, + ), ), ], ), ), ], ), - const Divider(height: 20), - _buildInfoRow('Hardware', hardware), - _buildInfoRow('Version', version ?? 'Unknown'), - if (appState.deviceModel != null) - _buildInfoRow('Platform', appState.deviceModel!.platform), - if (appState.devicePublicKey != null) + const SizedBox(height: 8), + + // Detail chips: hardware, version, platform + Wrap( + spacing: 6, + runSpacing: 4, + children: [ + _buildDetailChip(context, Icons.memory, hardware), + if (version != null) _buildDetailChip(context, Icons.code, version), + if (platform != null) _buildDetailChip(context, Icons.developer_board, platform), + ], + ), + + // Power level row + const SizedBox(height: 4), + _buildPowerRow(context, appState, isPowerSet, isAutoMode, prefs), + + // Public key row + if (appState.devicePublicKey != null) ...[ + const SizedBox(height: 8), _buildPublicKeyRow(context, appState.devicePublicKey!), - if (appState.authType != null && !appState.offlineMode) + ], + + // Registered via row + if (appState.authType != null && !appState.offlineMode) ...[ + const SizedBox(height: 4), _buildAuthTypeRow(context, appState.authType!), + ], ], ), ), ); - // Build disconnect button - final disconnectButton = ElevatedButton.icon( - onPressed: () async { - await appState.disconnect(); - }, - icon: const Icon(Icons.bluetooth_disabled), - label: const Text('Disconnect'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - ), + // Compact channels card + final channelsCard = RegionalConfigCard( + zoneName: appState.offlineMode ? null : appState.zoneName, + zoneCode: appState.offlineMode ? null : appState.zoneCode, + channels: appState.offlineMode ? [] : appState.regionalChannels, + scope: appState.offlineMode ? null : appState.scope, + isOfflineMode: appState.offlineMode, + compact: true, ); if (isLandscape) { - // Landscape: two-column layout return SafeArea( child: Padding( padding: const EdgeInsets.all(12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Left column: device info + disconnect Expanded( - child: Column( - children: [ - Expanded( - child: SingleChildScrollView( - child: deviceInfoCard, - ), - ), - const SizedBox(height: 8), - SizedBox( - width: double.infinity, - child: disconnectButton, - ), - ], - ), + child: SingleChildScrollView(child: deviceSummaryCard), ), const SizedBox(width: 12), - // Right column: power + regional config Expanded( - child: SingleChildScrollView( - child: Column( - children: [ - _buildPowerLevelCard(context, appState), - const SizedBox(height: 12), - RegionalConfigCard( - zoneName: appState.offlineMode ? null : appState.zoneName, - zoneCode: appState.offlineMode ? null : appState.zoneCode, - channels: appState.offlineMode ? [] : appState.regionalChannels, - scope: appState.offlineMode ? null : appState.scope, - isOfflineMode: appState.offlineMode, - ), - ], - ), - ), + child: SingleChildScrollView(child: channelsCard), ), ], ), @@ -402,78 +437,110 @@ class _ConnectionScreenState extends State with WidgetsBinding ); } - // Portrait: vertical layout - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + // Portrait: compact vertical layout (bottom bar provided by _buildBody) + return Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + deviceSummaryCard, + const SizedBox(height: 12), + channelsCard, + ], + ), + ); + } + + /// Power level row matching Registered via / Public Key format + Widget _buildPowerRow( + BuildContext context, + AppStateProvider appState, + bool isPowerSet, + bool isAutoMode, + UserPreferences prefs, + ) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: InkWell( + onTap: isAutoMode ? null : () => _showPowerLevelSelector(context, appState), + borderRadius: BorderRadius.circular(4), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ - const Expanded(child: OfflineModeToggle()), - const SizedBox(width: 4), - IconButton( - icon: Icon( - Icons.info_outline, - size: 20, - color: Theme.of(context).colorScheme.onSurfaceVariant, + const SizedBox( + width: 120, + child: Text( + 'Power Level', + style: TextStyle(fontWeight: FontWeight.w500), ), - tooltip: 'About Offline Mode', - onPressed: () => _showOfflineModeInfo(context), - visualDensity: VisualDensity.compact, - padding: EdgeInsets.zero, - constraints: const BoxConstraints(minWidth: 32, minHeight: 32), ), - ], - ), - ), - Expanded( - child: ListView( - padding: const EdgeInsets.all(16), - children: [ - deviceInfoCard, - const SizedBox(height: 16), - _buildPowerLevelCard(context, appState), - const SizedBox(height: 16), - RegionalConfigCard( - zoneName: appState.offlineMode ? null : appState.zoneName, - zoneCode: appState.offlineMode ? null : appState.zoneCode, - channels: appState.offlineMode ? [] : appState.regionalChannels, - scope: appState.offlineMode ? null : appState.scope, - isOfflineMode: appState.offlineMode, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.bolt, size: 16, color: isPowerSet ? Colors.amber.shade700 : Colors.orange), + const SizedBox(width: 4), + Text( + isPowerSet ? prefs.powerLevelDisplay : 'Unknown - tap to set', + style: TextStyle( + fontWeight: FontWeight.w500, + color: isPowerSet ? null : Colors.orange, + ), + ), + if (prefs.autoPowerSet) ...[ + const SizedBox(width: 4), + const Icon(Icons.auto_awesome, size: 14, color: Colors.green), + const SizedBox(width: 2), + const Text( + 'Auto', + style: TextStyle( + fontSize: 12, + color: Colors.green, + fontWeight: FontWeight.bold, + ), + ), + ], + if (!isAutoMode) ...[ + const SizedBox(width: 4), + const Icon(Icons.chevron_right, size: 16, color: Colors.grey), + ], + ], ), ], ), ), - Padding( - padding: const EdgeInsets.all(16), - child: SizedBox( - width: double.infinity, - child: disconnectButton, - ), - ), - ], + ), ); } - Widget _buildInfoRow(String label, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), + /// Small detail chip with icon + text + Widget _buildDetailChip(BuildContext context, IconData icon, String text) { + final theme = Theme.of(context); + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(8), + ), child: Row( + mainAxisSize: MainAxisSize.min, children: [ - SizedBox( - width: 120, - child: Text( - label, - style: const TextStyle(fontWeight: FontWeight.w500), + Icon(icon, size: 12, color: theme.colorScheme.onSurfaceVariant), + const SizedBox(width: 4), + Text( + text, + style: TextStyle( + fontSize: 11, + color: theme.colorScheme.onSurfaceVariant, ), ), - Expanded(child: Text(value)), ], ), ); } + + Widget _buildPublicKeyRow(BuildContext context, String publicKey) { // Show truncated key for display (first 8 + ... + last 8) final displayKey = publicKey.length > 16 @@ -597,32 +664,6 @@ class _ConnectionScreenState extends State with WidgetsBinding ); } - void _showOfflineModeInfo(BuildContext context) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Row( - children: [ - Icon(Icons.cloud_off, color: Colors.orange, size: 22), - SizedBox(width: 8), - Text('Offline Mode'), - ], - ), - content: const Text( - 'Save pings locally instead of uploading immediately. Useful when you have poor cell connectivity or the API is in maintenance.\n\n' - 'Data is stored on your device and can be uploaded later from the Settings tab when connectivity is restored.', - style: TextStyle(fontSize: 14, height: 1.5), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Got it'), - ), - ], - ), - ); - } - void _showAuthMethodInfo(BuildContext context, String currentType) { showModalBottomSheet( context: context, @@ -791,50 +832,6 @@ class _ConnectionScreenState extends State with WidgetsBinding ); } - Widget _buildPowerLevelCard(BuildContext context, AppStateProvider appState) { - final prefs = appState.preferences; - final isAutoMode = appState.autoPingEnabled; - final isPowerSet = prefs.autoPowerSet || prefs.powerLevelSet || appState.deviceModel != null; - - return Card( - child: ListTile( - leading: const Icon(Icons.power), - title: const Text('Power Level'), - subtitle: Builder( - builder: (context) { - if (!isPowerSet) { - return Text( - 'Unknown hardware - select power', - style: TextStyle(color: Colors.orange.shade700), - ); - } - return Row( - children: [ - Text(prefs.powerLevelDisplay), - if (prefs.autoPowerSet) ...[ - const SizedBox(width: 8), - const Icon(Icons.auto_awesome, size: 14, color: Colors.green), - const SizedBox(width: 4), - const Text( - 'Auto', - style: TextStyle( - fontSize: 12, - color: Colors.green, - fontWeight: FontWeight.bold, - ), - ), - ], - ], - ); - }, - ), - trailing: const Icon(Icons.chevron_right), - enabled: !isAutoMode, - onTap: isAutoMode ? null : () => _showPowerLevelSelector(context, appState), - ), - ); - } - void _showPowerLevelSelector(BuildContext context, AppStateProvider appState) { final prefs = appState.preferences; final deviceModel = appState.deviceModel; @@ -1233,103 +1230,89 @@ class _ConnectionScreenState extends State with WidgetsBinding // Show maintenance message (takes priority over zone checks) if (appState.maintenanceMode && !appState.offlineMode) { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.all(24), - child: Column( + return Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.engineering, + size: 64, + color: Colors.orange.withValues(alpha: 0.7), + ), + const SizedBox(height: 16), + const Text( + 'Maintenance Mode', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + appState.maintenanceMessage ?? 'Service is temporarily unavailable.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + const SizedBox(height: 32), + // Primary action: Enable Offline Mode + FilledButton.icon( + onPressed: () => appState.setOfflineMode(true), + icon: const Icon(Icons.cloud_off), + label: const Text('Enable Offline Mode'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + ), + ), + if (appState.maintenanceUrl != null) ...[ + const SizedBox(height: 12), + OutlinedButton.icon( + onPressed: () => _launchMaintenanceUrl(appState.maintenanceUrl!), + icon: const Icon(Icons.open_in_new, size: 18), + label: const Text('More Info'), + ), + ], + const SizedBox(height: 32), + // Info note at bottom + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.withValues(alpha: 0.3)), + ), + child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - Icons.engineering, - size: 64, - color: Colors.orange.withValues(alpha: 0.7), - ), - const SizedBox(height: 16), - const Text( - 'Maintenance Mode', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Text( - appState.maintenanceMessage ?? 'Service is temporarily unavailable.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Colors.grey.shade600, - ), - ), - const SizedBox(height: 32), - // Primary action: Enable Offline Mode - FilledButton.icon( - onPressed: () => appState.setOfflineMode(true), - icon: const Icon(Icons.cloud_off), - label: const Text('Enable Offline Mode'), - style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - ), - ), - if (appState.maintenanceUrl != null) ...[ - const SizedBox(height: 12), - OutlinedButton.icon( - onPressed: () => _launchMaintenanceUrl(appState.maintenanceUrl!), - icon: const Icon(Icons.open_in_new, size: 18), - label: const Text('More Info'), - ), - ], - const SizedBox(height: 32), - // Info note at bottom - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.blue.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.blue.withValues(alpha: 0.3)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.info_outline, size: 18, color: Colors.blue.shade700), - const SizedBox(width: 8), - Flexible( - child: Text( - 'Wardrive offline now, upload when service is restored.', - style: TextStyle(fontSize: 13, color: Colors.blue.shade700), - ), - ), - ], + Icon(Icons.info_outline, size: 18, color: Colors.blue.shade700), + const SizedBox(width: 8), + Flexible( + child: Text( + 'Wardrive offline now, upload when service is restored.', + style: TextStyle(fontSize: 13, color: Colors.blue.shade700), ), ), ], ), ), - ), + ], ), - ], + ), ); } // Show Bluetooth off message (takes priority over zone checks) if (appState.isBluetoothOff) { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.bluetooth_disabled, - iconColor: Colors.red.withValues(alpha: 0.7), - title: 'Bluetooth is Off', - message: 'Please enable Bluetooth to scan for MeshCore devices.', - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.bluetooth_disabled, + iconColor: Colors.red.withValues(alpha: 0.7), + title: 'Bluetooth is Off', + message: 'Please enable Bluetooth to scan for MeshCore devices.', ); } @@ -1347,24 +1330,17 @@ class _ConnectionScreenState extends State with WidgetsBinding message += '\n\nNearest zone is $zoneDisplay, $dist away.'; } - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.public_off, - iconColor: Colors.orange.withValues(alpha: 0.7), - title: 'Region Not Available', - message: message, - action: OutlinedButton.icon( - onPressed: () => _launchOnboardingUrl(), - icon: const Icon(Icons.open_in_new, size: 18), - label: const Text('Request Region Onboarding'), - ), - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.public_off, + iconColor: Colors.orange.withValues(alpha: 0.7), + title: 'Region Not Available', + message: message, + action: OutlinedButton.icon( + onPressed: () => _launchOnboardingUrl(), + icon: const Icon(Icons.open_in_new, size: 18), + label: const Text('Request Region Onboarding'), + ), ); } @@ -1375,158 +1351,129 @@ class _ConnectionScreenState extends State with WidgetsBinding // Network error — show offline mode option (matches maintenance pattern) if (appState.zoneCheckErrorReason == 'network') { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.all(24), - child: Column( + return Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.wifi_off, + size: 64, + color: Colors.deepOrange.withValues(alpha: 0.7), + ), + const SizedBox(height: 16), + const Text( + 'No Internet Connection', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + 'Unable to reach MeshMapper. Check your connection, or wardrive offline.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + const SizedBox(height: 8), + Text( + countdown > 0 + ? 'Retrying in ${countdown}s...' + : 'Retrying...', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade500, + ), + ), + const SizedBox(height: 32), + FilledButton.icon( + onPressed: () => appState.setOfflineMode(true), + icon: const Icon(Icons.cloud_off), + label: const Text('Enable Offline Mode'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + ), + ), + const SizedBox(height: 32), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.withValues(alpha: 0.3)), + ), + child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - Icons.wifi_off, - size: 64, - color: Colors.deepOrange.withValues(alpha: 0.7), - ), - const SizedBox(height: 16), - const Text( - 'No Internet Connection', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Text( - 'Unable to reach MeshMapper. Check your connection, or wardrive offline.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Colors.grey.shade600, - ), - ), - const SizedBox(height: 8), - Text( - countdown > 0 - ? 'Retrying in ${countdown}s...' - : 'Retrying...', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Colors.grey.shade500, - ), - ), - const SizedBox(height: 32), - FilledButton.icon( - onPressed: () => appState.setOfflineMode(true), - icon: const Icon(Icons.cloud_off), - label: const Text('Enable Offline Mode'), - style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - ), - ), - const SizedBox(height: 32), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.blue.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.blue.withValues(alpha: 0.3)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.info_outline, size: 18, color: Colors.blue.shade700), - const SizedBox(width: 8), - Flexible( - child: Text( - 'Wardrive offline now, upload when service is restored.', - style: TextStyle(fontSize: 13, color: Colors.blue.shade700), - ), - ), - ], + Icon(Icons.info_outline, size: 18, color: Colors.blue.shade700), + const SizedBox(width: 8), + Flexible( + child: Text( + 'Wardrive offline now, upload when service is restored.', + style: TextStyle(fontSize: 13, color: Colors.blue.shade700), ), ), ], ), ), - ), + ], ), - ], + ), ); } // GPS errors — no auto-retry, show manual retry button if (appState.zoneCheckErrorReason == 'gps_inaccurate' || appState.zoneCheckErrorReason == 'gps_stale') { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.gps_off, - iconColor: Colors.orange.withValues(alpha: 0.7), - title: appState.zoneCheckErrorReason == 'gps_inaccurate' - ? 'GPS Accuracy Error' - : 'GPS Stale Error', - message: '${appState.zoneCheckError}\n\nTry moving to an area with better GPS signal, then tap retry.', - action: FilledButton.icon( - onPressed: () => appState.checkZoneStatus(), - icon: const Icon(Icons.refresh), - label: const Text('Retry Zone Check'), - style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - ), - ), - ), + return _buildMessageContent( + context: context, + icon: Icons.gps_off, + iconColor: Colors.orange.withValues(alpha: 0.7), + title: appState.zoneCheckErrorReason == 'gps_inaccurate' + ? 'GPS Accuracy Error' + : 'GPS Stale Error', + message: '${appState.zoneCheckError}\n\nTry moving to an area with better GPS signal, then tap retry.', + action: FilledButton.icon( + onPressed: () => appState.checkZoneStatus(), + icon: const Icon(Icons.refresh), + label: const Text('Retry Zone Check'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), ), - ], + ), ); } // Other non-network errors — show simple error with countdown - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.cloud_off, - iconColor: Colors.orange.withValues(alpha: 0.7), - title: 'Zone Check Failed', - message: countdown > 0 - ? '${appState.zoneCheckError}\n\nChecking again in ${countdown}s...' - : '${appState.zoneCheckError}\n\nRetrying...', - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.cloud_off, + iconColor: Colors.orange.withValues(alpha: 0.7), + title: 'Zone Check Failed', + message: countdown > 0 + ? '${appState.zoneCheckError}\n\nChecking again in ${countdown}s...' + : '${appState.zoneCheckError}\n\nRetrying...', ); } // Zone check in progress or waiting for GPS - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.location_searching, - iconColor: Colors.blue.withValues(alpha: 0.7), - title: 'Checking MeshMapper Zone...', - message: 'Verifying your location with MeshMapper', - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.location_searching, + iconColor: Colors.blue.withValues(alpha: 0.7), + title: 'Checking MeshMapper Zone...', + message: 'Verifying your location with MeshMapper', ); } if (appState.isScanning) { return Column( children: [ - _buildZoneStatusBar(context, appState), const LinearProgressIndicator(), Expanded(child: _buildDeviceListView(context, appState, canConnect: canConnect)), ], @@ -1537,12 +1484,7 @@ class _ConnectionScreenState extends State with WidgetsBinding // Show remembered device option if available (mobile only) final remembered = appState.rememberedDevice; if (!kIsWeb && remembered != null) { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded(child: _buildRememberedDeviceView(context, appState, remembered, canConnect: canConnect)), - ], - ); + return _buildRememberedDeviceView(context, appState, remembered, canConnect: canConnect); } // Show GPS disabled message when location services are off @@ -1550,74 +1492,48 @@ class _ConnectionScreenState extends State with WidgetsBinding // iOS doesn't allow opening Location Services directly, so no button on iOS final isIOS = !kIsWeb && Platform.isIOS; - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.gps_off, - iconColor: Colors.red.withValues(alpha: 0.7), - title: 'Location Services Disabled', - message: 'Please enable Location Services to verify you\'re in an allowed zone.', - action: isIOS - ? null - : ElevatedButton.icon( - onPressed: () => Geolocator.openLocationSettings(), - icon: const Icon(Icons.settings), - label: const Text('Open Location Settings'), - ), - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.gps_off, + iconColor: Colors.red.withValues(alpha: 0.7), + title: 'Location Services Disabled', + message: 'Please enable Location Services to verify you\'re in an allowed zone.', + action: isIOS + ? null + : ElevatedButton.icon( + onPressed: () => Geolocator.openLocationSettings(), + icon: const Icon(Icons.settings), + label: const Text('Open Location Settings'), + ), ); } // Show GPS permission required message when permissions are denied if (appState.gpsStatus == GpsStatus.permissionDenied) { - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.location_off, - iconColor: Colors.orange.withValues(alpha: 0.7), - title: 'GPS Permission Required', - message: 'Location access is needed to verify you\'re in an allowed zone.', - action: ElevatedButton.icon( - onPressed: () => _requestLocationPermission(appState), - icon: const Icon(Icons.location_on), - label: const Text('Enable Location'), - ), - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.location_off, + iconColor: Colors.orange.withValues(alpha: 0.7), + title: 'GPS Permission Required', + message: 'Location access is needed to verify you\'re in an allowed zone.', + action: ElevatedButton.icon( + onPressed: () => _requestLocationPermission(appState), + icon: const Icon(Icons.location_on), + label: const Text('Enable Location'), + ), ); } - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded( - child: _buildMessageContent( - context: context, - icon: Icons.bluetooth_searching, - iconColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.5), - title: 'No devices found', - message: 'Tap Scan to search for MeshCore devices', - ), - ), - ], + return _buildMessageContent( + context: context, + icon: Icons.bluetooth_searching, + iconColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.5), + title: 'No devices found', + message: 'Tap Scan to search for MeshCore devices', ); } - return Column( - children: [ - _buildZoneStatusBar(context, appState), - Expanded(child: _buildDeviceListView(context, appState, canConnect: canConnect)), - ], - ); + return _buildDeviceListView(context, appState, canConnect: canConnect); } void _launchOnboardingUrl() async { diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 8913478..9a5b390 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -423,15 +423,26 @@ class _SettingsScreenState extends State { ), // Offline Sessions - if (appState.offlineSessions.isNotEmpty) ...[ - _buildSectionHeader(context, 'Offline Sessions'), + _buildSectionHeader(context, 'Offline Sessions'), + if (appState.offlineSessions.isEmpty) + ListTile( + leading: Icon(Icons.cloud_off, color: Colors.grey.shade400), + title: Text( + 'No offline sessions stored', + style: TextStyle(color: Colors.grey.shade500), + ), + subtitle: Text( + 'Sessions recorded in offline mode will appear here for upload', + style: TextStyle(fontSize: 12, color: Colors.grey.shade400), + ), + ) + else ...appState.offlineSessions.map((session) => _OfflineSessionTile( session: session, onUpload: () => _uploadOfflineSession(context, appState, session.filename), onDelete: () => _confirmDeleteOfflineSession(context, appState, session.filename), onDownload: () => _downloadOfflineSession(context, appState, session.filename), )), - ], const Divider(), diff --git a/lib/widgets/offline_mode_toggle.dart b/lib/widgets/offline_mode_toggle.dart index c088ab4..cfdb9cb 100644 --- a/lib/widgets/offline_mode_toggle.dart +++ b/lib/widgets/offline_mode_toggle.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import '../providers/app_state_provider.dart'; /// Shared offline mode toggle widget -/// Extracted from ping_controls.dart for use on both connection screen and ping controls +/// Compact button style — icon + label, tappable to toggle with confirmation class OfflineModeToggle extends StatelessWidget { const OfflineModeToggle({super.key}); @@ -17,6 +17,10 @@ class OfflineModeToggle extends StatelessWidget { ) async { final newMode = !currentOfflineMode; + // Always show confirmation dialog + final confirmed = await _showConfirmDialog(context, newMode); + if (confirmed != true || !context.mounted) return; + // If connected, show progress dialog during mode switch if (isConnected) { final statusText = newMode @@ -79,114 +83,95 @@ class OfflineModeToggle extends StatelessWidget { } } + /// Show confirmation dialog explaining what the mode does + static Future _showConfirmDialog(BuildContext context, bool switchingToOffline) { + final title = switchingToOffline ? 'Enable Offline Mode?' : 'Switch to Online Mode?'; + final icon = switchingToOffline ? Icons.cloud_off : Icons.cloud_done; + final iconColor = switchingToOffline ? Colors.orange : Colors.green; + final description = switchingToOffline + ? 'Wardrive data will be saved locally on your device instead of uploading to MeshMapper.\n\n' + 'This is useful when you have poor cell connectivity or the API is in maintenance.\n\n' + 'You can upload saved data later from the Settings tab.' + : 'Wardrive data will be uploaded to MeshMapper immediately as you drive.\n\n' + 'This requires an active internet connection.'; + final confirmLabel = switchingToOffline ? 'Go Offline' : 'Go Online'; + + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: Row( + children: [ + Icon(icon, color: iconColor, size: 22), + const SizedBox(width: 8), + Flexible(child: Text(title)), + ], + ), + content: Text( + description, + style: const TextStyle(fontSize: 14, height: 1.5), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Cancel'), + ), + FilledButton( + onPressed: () => Navigator.pop(context, true), + style: switchingToOffline + ? FilledButton.styleFrom(backgroundColor: Colors.orange) + : null, + child: Text(confirmLabel), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; final appState = context.watch(); final offlineMode = appState.offlineMode; - final offlinePingCount = appState.offlinePingCount; final isConnected = appState.isConnected; + final color = offlineMode + ? (isDark ? Colors.orange.shade400 : Colors.orange.shade700) + : (isDark ? Colors.green.shade400 : Colors.green.shade700); + final bgColor = offlineMode + ? Colors.orange.withValues(alpha: 0.15) + : Colors.green.withValues(alpha: 0.15); + final borderColor = offlineMode + ? Colors.orange.withValues(alpha: 0.4) + : Colors.green.withValues(alpha: 0.4); + return Material( color: Colors.transparent, child: InkWell( onTap: () => handleOfflineModeToggle(context, appState, offlineMode, isConnected), borderRadius: BorderRadius.circular(10), child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.15) - : colorScheme.onSurface.withValues(alpha: 0.05), + color: bgColor, borderRadius: BorderRadius.circular(10), - border: Border.all( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.4) - : colorScheme.outline.withValues(alpha: 0.2), - ), + border: Border.all(color: borderColor), ), child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ - // Icon - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: offlineMode - ? Colors.orange.withValues(alpha: 0.2) - : colorScheme.onSurface.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(6), - ), - child: Icon( - offlineMode ? Icons.cloud_off : Icons.cloud_queue, - size: 18, - color: offlineMode - ? (isDark ? Colors.orange.shade400 : Colors.orange.shade700) - : colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 12), - // Label and count - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Offline Mode', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: offlineMode - ? (isDark ? Colors.orange.shade300 : Colors.orange.shade800) - : colorScheme.onSurface, - ), - ), - if (offlineMode && offlinePingCount > 0) - Text( - '$offlinePingCount pings saved locally', - style: TextStyle( - fontSize: 11, - color: isDark ? Colors.orange.shade400 : Colors.orange.shade600, - ), - ) - else - Text( - offlineMode - ? 'Data saved locally' - : 'Uploads immediately', - style: TextStyle( - fontSize: 11, - color: colorScheme.onSurfaceVariant, - ), - ), - ], - ), + Icon( + offlineMode ? Icons.cloud_off : Icons.cloud_queue, + size: 18, + color: color, ), - // Toggle indicator - Container( - width: 44, - height: 26, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - color: offlineMode - ? (isDark ? Colors.orange.shade600 : Colors.orange.shade500) - : (isDark ? const Color(0xFF475569) : const Color(0xFFCBD5E1)), - ), - child: AnimatedAlign( - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut, - alignment: offlineMode - ? Alignment.centerRight - : Alignment.centerLeft, - child: Container( - width: 22, - height: 22, - margin: const EdgeInsets.all(2), - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - ), - ), + const SizedBox(width: 8), + Text( + offlineMode ? 'Offline' : 'Online', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: color, ), ), ], diff --git a/lib/widgets/regional_config_card.dart b/lib/widgets/regional_config_card.dart index bdc9b31..10a909e 100644 --- a/lib/widgets/regional_config_card.dart +++ b/lib/widgets/regional_config_card.dart @@ -8,6 +8,7 @@ class RegionalConfigCard extends StatelessWidget { final List channels; final String? scope; final bool isOfflineMode; + final bool compact; const RegionalConfigCard({ super.key, @@ -16,10 +17,15 @@ class RegionalConfigCard extends StatelessWidget { this.channels = const [], this.scope, this.isOfflineMode = false, + this.compact = false, }); @override Widget build(BuildContext context) { + if (compact) { + return _buildCompact(context); + } + // When offline mode is enabled, show "-" for zone fields final displayZoneName = isOfflineMode ? '-' : (zoneName ?? 'Not configured'); final displayZoneCode = isOfflineMode ? '-' : zoneCode; @@ -108,6 +114,93 @@ class RegionalConfigCard extends StatelessWidget { ); } + /// Compact mode: "Regional Settings" header, scope row, channel chips + Widget _buildCompact(BuildContext context) { + final displayZone = isOfflineMode ? null : zoneName; + final displayScope = isOfflineMode ? '-' : (scope ?? 'Global'); + + return Card( + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header + Row( + children: [ + Icon( + Icons.public, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + const SizedBox(width: 8), + Text( + 'Regional Settings', + style: Theme.of(context).textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + const Spacer(), + if (displayZone != null) + Text( + displayZone, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + const SizedBox(height: 10), + + // Scope row + _buildCompactRow(context, 'Scope', [ + _buildChannelChip(context, displayScope, isDefault: true), + ]), + const SizedBox(height: 8), + + // Channels row + _buildCompactRow(context, 'Channels', [ + _buildChannelChip(context, 'Public', isDefault: true), + _buildChannelChip(context, '#wardriving', isDefault: true), + if (!isOfflineMode) + ...channels.map((c) => _buildChannelChip(context, c)), + ]), + ], + ), + ), + ); + } + + /// Compact labeled row: small label on left, chips on right + Widget _buildCompactRow(BuildContext context, String label, List chips) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 70, + child: Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + label, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + ), + Expanded( + child: Wrap( + spacing: 6, + runSpacing: 6, + children: chips, + ), + ), + ], + ); + } + Widget _buildInfoRow(BuildContext context, IconData icon, String label, String? value, {bool isOffline = false}) { return Row( @@ -130,8 +223,12 @@ class RegionalConfigCard extends StatelessWidget { } Widget _buildChannelChip(BuildContext context, String name, {bool isDefault = false}) { - // Public channel doesn't use # prefix + // Public channel doesn't use # prefix; scope/plain values pass through as-is final displayName = name == 'Public' ? name : (name.startsWith('#') ? name : '#$name'); + // If it doesn't look like a channel name, show raw value (e.g. scope "Global") + final isChannel = name.startsWith('#') || name == 'Public'; + final label = isChannel ? displayName : name; + return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( @@ -146,11 +243,10 @@ class RegionalConfigCard extends StatelessWidget { ), ), child: Text( - displayName, + label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, - // Use onPrimaryContainer for proper contrast on primaryContainer background color: isDefault ? Colors.grey : Theme.of(context).colorScheme.onPrimaryContainer, ), ), From d5243a1323fa32399b1388c0b61d28fe440ce92c Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 18:55:05 -0400 Subject: [PATCH 41/57] ### Bug Fixes - Fixed offline wardrive pings being lost when the app was killed by the OS, backgrounded, or disconnected mid-session - Offline pings now auto-save periodically, so at most ~60 seconds of data is lost in a worst-case app kill - Disconnecting while in offline mode now saves accumulated pings before cleanup - App backgrounding/suspension now triggers an immediate save of offline ping data --- lib/providers/app_state_provider.dart | 56 +++++++++++++++++++ lib/services/api_queue_service.dart | 6 ++ lib/services/offline_session_service.dart | 68 +++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 7be9c97..0a8a30b 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -233,6 +233,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { Timer? _reconnectTimer; Timer? _reconnectTimeoutTimer; Timer? _restoreAutoPingTimer; + Timer? _offlineAutoSaveTimer; bool _autoPingWasEnabled = false; AutoMode _autoModeBeforeReconnect = AutoMode.active; int _reconnectRestoreGeneration = 0; @@ -283,6 +284,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { debugLog('[APP] App resumed from background'); + } else if (state == AppLifecycleState.paused) { + debugLog('[APP] App paused (backgrounded)'); + // Save offline pings immediately on pause to prevent data loss if OS kills app + if (_preferences.offlineMode && _apiQueueService.offlinePingCount > 0) { + _autoSaveOfflinePings(); + } } } @@ -2260,6 +2267,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Stop RX wardriving if active (flushes batches to queue) _rxLogger?.stopWardriving(trigger: 'disconnect'); + // Save offline pings before clearing queue (no-op if not in offline mode or no pings) + await _saveOfflineSession(); + // ALWAYS START FRESH - clear any queued data on disconnect // Pings without a valid session cannot be uploaded later await _apiQueueService.clearOnDisconnect(); @@ -2703,6 +2713,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Offline mode ${enabled ? 'enabled' : 'disabled'}'); if (enabled) { + // Start periodic auto-save to prevent data loss from app kill + _startOfflineAutoSaveTimer(); // Clear zone data when entering offline mode _inZone = null; _currentZone = null; @@ -2710,6 +2722,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _lastZoneCheckPosition = null; debugLog('[GEOFENCE] Cleared zone data for offline mode'); } else { + // Stop auto-save timer when leaving offline mode + _stopOfflineAutoSaveTimer(); // Re-check zone status when exiting offline mode if (_currentPosition != null) { debugLog('[GEOFENCE] Re-checking zone status after offline mode disabled'); @@ -2762,6 +2776,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _preferences = _preferences.copyWith(offlineMode: true); _apiQueueService.offlineMode = true; + // 5b. Start periodic auto-save to prevent data loss from app kill + _startOfflineAutoSaveTimer(); + // 6. Clear zone data _inZone = null; _currentZone = null; @@ -3052,10 +3069,48 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { deviceName: offlineDeviceName, contactUri: _offlineContactUri, ); + _offlineSessionService.finalizeCurrentSession(); debugLog('[APP] Saved offline session with ${pings.length} pings'); + _stopOfflineAutoSaveTimer(); notifyListeners(); } + /// Periodically auto-save offline pings to prevent data loss from app kill. + /// Uses a non-destructive snapshot so in-memory accumulation continues. + void _autoSaveOfflinePings() { + if (!_preferences.offlineMode || _apiQueueService.offlinePingCount == 0) return; + + final pings = _apiQueueService.getOfflinePingsSnapshot(); + if (pings.isEmpty) return; + + final offlineDeviceName = _isAnonymousRenamed + ? _originalDeviceName + : (_meshCoreConnection?.selfInfo?.name ?? connectedDeviceName?.replaceFirst('MeshCore-', '')); + + _offlineSessionService.updateCurrentSession( + pings, + devicePublicKey: _devicePublicKey, + deviceName: offlineDeviceName, + contactUri: _offlineContactUri, + ); + } + + void _startOfflineAutoSaveTimer() { + _offlineAutoSaveTimer?.cancel(); + _offlineAutoSaveTimer = Timer.periodic(const Duration(seconds: 60), (_) { + _autoSaveOfflinePings(); + }); + debugLog('[OFFLINE] Auto-save timer started (60s interval)'); + } + + void _stopOfflineAutoSaveTimer() { + if (_offlineAutoSaveTimer != null) { + _offlineAutoSaveTimer!.cancel(); + _offlineAutoSaveTimer = null; + debugLog('[OFFLINE] Auto-save timer stopped'); + } + } + /// Upload a stored offline session Future uploadOfflineSession(String filename) async { final sessionData = _offlineSessionService.getSessionData(filename); @@ -4643,6 +4698,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _reconnectTimer?.cancel(); _reconnectTimeoutTimer?.cancel(); _restoreAutoPingTimer?.cancel(); + _offlineAutoSaveTimer?.cancel(); _tileRefreshTimer?.cancel(); _unifiedRxHandler?.dispose(); _meshCoreConnection?.dispose(); diff --git a/lib/services/api_queue_service.dart b/lib/services/api_queue_service.dart index 613fc5b..2cb45fa 100644 --- a/lib/services/api_queue_service.dart +++ b/lib/services/api_queue_service.dart @@ -670,6 +670,12 @@ class ApiQueueService { return [...hiveItems, ...memoryItems]; } + /// Get a snapshot of accumulated offline pings without clearing. + /// Used for periodic auto-saves to persist data without losing the in-memory accumulator. + List> getOfflinePingsSnapshot() { + return List>.from(_offlinePings); + } + /// Get accumulated offline pings and clear the accumulator /// Returns the list of ping JSON objects collected during offline session List> getAndClearOfflinePings() { diff --git a/lib/services/offline_session_service.dart b/lib/services/offline_session_service.dart index 3df1b90..d37cd8d 100644 --- a/lib/services/offline_session_service.dart +++ b/lib/services/offline_session_service.dart @@ -83,6 +83,10 @@ class OfflineSessionService { SharedPreferences? _prefs; List _sessions = []; + /// Tracks the filename of the session currently being accumulated via periodic auto-save. + /// When set, `updateCurrentSession()` updates this session in-place instead of creating a new one. + String? _currentSessionFilename; + /// Callback when sessions list changes void Function(List sessions)? onSessionsUpdated; @@ -182,6 +186,70 @@ class OfflineSessionService { debugLog('[OFFLINE] Saved session: $filename with ${pings.length} pings (device: ${deviceName ?? "unknown"})'); } + /// Update the current in-progress session with the latest pings snapshot. + /// If no current session exists, creates a new one and tracks it. + /// This allows periodic saves to update the same file instead of creating duplicates. + Future updateCurrentSession( + List> pings, { + String? devicePublicKey, + String? deviceName, + String? contactUri, + }) async { + if (pings.isEmpty) { + debugLog('[OFFLINE] No pings to auto-save, skipping'); + return; + } + + // If we have a tracked session, update it in-place + if (_currentSessionFilename != null) { + final index = _sessions.indexWhere((s) => s.filename == _currentSessionFilename); + if (index != -1) { + final existing = _sessions[index]; + final updatedData = Map.from(existing.data); + updatedData['pings'] = pings; + updatedData['ping_count'] = pings.length; + + _sessions[index] = OfflineSession( + filename: existing.filename, + createdAt: existing.createdAt, + pingCount: pings.length, + data: updatedData, + devicePublicKey: devicePublicKey ?? existing.devicePublicKey, + deviceName: deviceName ?? existing.deviceName, + contactUri: contactUri ?? existing.contactUri, + ); + await _saveSessions(); + debugLog('[OFFLINE] Updated session: ${existing.filename} with ${pings.length} pings'); + return; + } + // Session was deleted externally — fall through to create new + debugWarn('[OFFLINE] Tracked session $_currentSessionFilename not found, creating new'); + _currentSessionFilename = null; + } + + // No current session — create a new one and track it + await saveSession( + pings, + devicePublicKey: devicePublicKey, + deviceName: deviceName, + contactUri: contactUri, + ); + // saveSession inserts at index 0 (newest first) + if (_sessions.isNotEmpty) { + _currentSessionFilename = _sessions.first.filename; + debugLog('[OFFLINE] Tracking new auto-save session: $_currentSessionFilename'); + } + } + + /// Clear the current session tracker so the next save creates a fresh session file. + /// Called after final saves (mode switch, disconnect) to create a clean break. + void finalizeCurrentSession() { + if (_currentSessionFilename != null) { + debugLog('[OFFLINE] Finalized session: $_currentSessionFilename'); + _currentSessionFilename = null; + } + } + /// Mark a session as uploaded without deleting it Future markAsUploaded(String filename) async { final index = _sessions.indexWhere((s) => s.filename == filename); From 5d58025286906b101e45c2ded112ce72a1a635b9 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 19:09:08 -0400 Subject: [PATCH 42/57] =?UTF-8?q?=20=20Bug=201=20=E2=80=94=20Trace=20Mode?= =?UTF-8?q?=20fails=20after=20path=20byte=20mode=20switch:=20=20=20-=20lib?= =?UTF-8?q?/services/ping=5Fservice.dart:71:=20Changed=20final=20int=20=5F?= =?UTF-8?q?hopBytes=20to=20int=20=20=20=5FhopBytes=20and=20added=20a=20set?= =?UTF-8?q?=20hopBytes=20setter=20=20=20-=20lib/providers/app=5Fstate=5Fpr?= =?UTF-8?q?ovider.dart:1961:=20Added=20=5FpingService=3F.hopBytes=20=3D=20?= =?UTF-8?q?=20=20newHopBytes;=20in=20=5FapplyLivePathHashMode()=20so=20Pin?= =?UTF-8?q?gService=20stays=20in=20sync=20when=20the=20=20=20=20user=20cha?= =?UTF-8?q?nges=20path=20mode=20at=20runtime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 2 — "No log files available" when only active log exists: - lib/widgets/upload_logs_dialog.dart:67: Changed DebugFileLogger.listUploadableLogFiles() to widget.appState.prepareDebugLogsForUpload() — this rotates the active log first (same pattern as BugReportSheet), so the rotated file appears in the list --- lib/providers/app_state_provider.dart | 1 + lib/services/ping_service.dart | 5 ++++- lib/widgets/upload_logs_dialog.dart | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 0a8a30b..bf8b5e5 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1958,6 +1958,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _hopBytes = newHopBytes; _userChangedPathMode = true; + _pingService?.hopBytes = newHopBytes; final mode = newHopBytes - 1; // Convert 1/2/3 → mode 0/1/2 _meshCoreConnection?.setPathHashMode(mode); debugLog('[PATH] User changed path mode to $newHopBytes-byte (sent to radio)'); diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index 5854468..e235392 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -68,7 +68,10 @@ class PingService { final bool Function(String repeaterId)? shouldIgnoreRepeater; /// Number of bytes per hop in path hash (1, 2, or 3). Passed to DiscTracker for repeater ID length. - final int _hopBytes; + int _hopBytes; + + /// Update hop bytes at runtime (e.g. when user changes path mode while connected) + set hopBytes(int value) => _hopBytes = value; /// When true, skip RSSI carpeater check in DiscTracker (user setting) bool disableRssiFilter; diff --git a/lib/widgets/upload_logs_dialog.dart b/lib/widgets/upload_logs_dialog.dart index f97ddae..4ba980e 100644 --- a/lib/widgets/upload_logs_dialog.dart +++ b/lib/widgets/upload_logs_dialog.dart @@ -64,7 +64,7 @@ class _UploadLogsSheetState extends State { Future _loadUploadableFiles() async { try { - final files = await DebugFileLogger.listUploadableLogFiles(); + final files = await widget.appState.prepareDebugLogsForUpload(); if (mounted) { setState(() { _availableLogFiles = files; From dc52c76cf8f0b9bef33e7cf6f874611153f7a59d Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 19:22:02 -0400 Subject: [PATCH 43/57] ### Improvements - Auto-ping now shows "Skipped Xs" when a ping is skipped due to insufficient movement (25m minimum), replacing the generic countdown label across all UI layouts --- lib/widgets/ping_controls.dart | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index 436610f..d0046da 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -36,6 +36,7 @@ class PingControls extends StatelessWidget { final isPingInProgress = appState.isPingInProgress; // True during entire ping + RX window (includes auto pings) final autoPingWaiting = appState.autoPingTimer.isRunning; // Waiting for next auto ping final autoPingRemaining = appState.autoPingTimer.remainingSec; + final autoPingSkipped = appState.autoPingTimer.skipReason != null; // Last ping was skipped (e.g. distance) final discoveryWindowActive = appState.discoveryWindowTimer.isRunning; // Discovery listening window countdown (Passive Mode) final discoveryWindowRemaining = appState.discoveryWindowTimer.remainingSec; @@ -147,7 +148,7 @@ class PingControls extends StatelessWidget { : rxWindowActive ? 'Listening ${rxWindowRemaining}s' // TX RX window : autoPingWaiting - ? 'Next ping ${autoPingRemaining}s' + ? (autoPingSkipped ? 'Skipped ${autoPingRemaining}s' : 'Next ping ${autoPingRemaining}s') : hybridEnabled ? 'Hybrid Mode' : 'Active Mode') : rxWindowActive ? 'Cooldown ${rxWindowRemaining}s' @@ -181,7 +182,7 @@ class PingControls extends StatelessWidget { ? (discoveryWindowActive ? 'Listening ${discoveryWindowRemaining}s' // During discovery listening window : autoPingWaiting - ? 'Next Disc ${autoPingRemaining}s' // Waiting for next discovery + ? (autoPingSkipped ? 'Skipped ${autoPingRemaining}s' : 'Next Disc ${autoPingRemaining}s') // Waiting for next discovery : 'Passive Mode') // Initial state before first discovery : isTxModeRunning || isPendingDisable ? 'Passive Mode' // Just disabled when Active/Hybrid Mode is running or stopping @@ -511,7 +512,9 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { if (discoveryWindowActive) { statusText = 'Listening ${discoveryRemaining}s'; } else if (autoPingWaiting) { - statusText = 'Next in ${autoPingRemaining}s'; + statusText = appState.autoPingTimer.skipReason != null + ? 'Skipped ${autoPingRemaining}s' + : 'Next in ${autoPingRemaining}s'; } } @@ -677,6 +680,7 @@ class _CompactPingControlsState extends State { final isPingInProgress = appState.isPingInProgress; final autoPingWaiting = appState.autoPingTimer.isRunning; final autoPingRemaining = appState.autoPingTimer.remainingSec; + final autoPingSkipped = appState.autoPingTimer.skipReason != null; final discoveryWindowActive = appState.discoveryWindowTimer.isRunning; final discoveryWindowRemaining = appState.discoveryWindowTimer.remainingSec; @@ -794,6 +798,7 @@ class _CompactPingControlsState extends State { cooldownActive: cooldownActive, cooldownRemaining: cooldownRemaining, isExpandedDuringCooldown: activeModeExpanded && cooldownActive, + isSkipped: autoPingSkipped, discoveryWindowActive: discoveryWindowActive, discoveryWindowRemaining: discoveryWindowRemaining, ), @@ -827,6 +832,7 @@ class _CompactPingControlsState extends State { cooldownActive: cooldownActive, cooldownRemaining: cooldownRemaining, isExpandedDuringCooldown: passiveModeExpanded && cooldownActive, + isSkipped: autoPingSkipped, ), color: isPassiveModeRunning ? const Color(0xFF22C55E) // green-500 @@ -857,6 +863,7 @@ class _CompactPingControlsState extends State { cooldownActive: cooldownActive, cooldownRemaining: cooldownRemaining, isExpandedDuringCooldown: traceModeExpanded && cooldownActive, + isSkipped: autoPingSkipped, ), color: isTargetedRunning ? const Color(0xFF22C55E) // green-500 @@ -959,6 +966,7 @@ class _CompactPingControlsState extends State { required bool cooldownActive, required int cooldownRemaining, required bool isExpandedDuringCooldown, + required bool isSkipped, bool discoveryWindowActive = false, int discoveryWindowRemaining = 0, }) { @@ -971,7 +979,7 @@ class _CompactPingControlsState extends State { if (discoveryWindowActive) return showFullText ? 'Listening ${discoveryWindowRemaining}s' : '${discoveryWindowRemaining}s'; if (isPingInProgress && !rxWindowActive) return showFullText ? 'Sending...' : '...'; if (rxWindowActive) return showFullText ? 'Listening ${rxWindowRemaining}s' : '${rxWindowRemaining}s'; - if (autoPingWaiting) return showFullText ? 'Waiting ${autoPingRemaining}s' : '${autoPingRemaining}s'; + if (autoPingWaiting) return showFullText ? (isSkipped ? 'Skipped ${autoPingRemaining}s' : 'Waiting ${autoPingRemaining}s') : '${autoPingRemaining}s'; } // Show cooldown if this button caused it if (cooldownActive && isExpandedDuringCooldown) { @@ -992,10 +1000,11 @@ class _CompactPingControlsState extends State { required bool cooldownActive, required int cooldownRemaining, required bool isExpandedDuringCooldown, + required bool isSkipped, }) { if (isPassiveModeRunning) { if (discoveryWindowActive) return showFullText ? 'Listening ${discoveryWindowRemaining}s' : '${discoveryWindowRemaining}s'; - if (autoPingWaiting) return showFullText ? 'Waiting ${autoPingRemaining}s' : '${autoPingRemaining}s'; + if (autoPingWaiting) return showFullText ? (isSkipped ? 'Skipped ${autoPingRemaining}s' : 'Waiting ${autoPingRemaining}s') : '${autoPingRemaining}s'; } // Show cooldown if this button caused it if (cooldownActive && isExpandedDuringCooldown) { @@ -1016,10 +1025,11 @@ class _CompactPingControlsState extends State { required bool cooldownActive, required int cooldownRemaining, required bool isExpandedDuringCooldown, + required bool isSkipped, }) { if (isTargetedRunning) { if (discoveryWindowActive) return showFullText ? 'Listening ${discoveryWindowRemaining}s' : '${discoveryWindowRemaining}s'; - if (autoPingWaiting) return showFullText ? 'Next in ${autoPingRemaining}s' : '${autoPingRemaining}s'; + if (autoPingWaiting) return showFullText ? (isSkipped ? 'Skipped ${autoPingRemaining}s' : 'Next in ${autoPingRemaining}s') : '${autoPingRemaining}s'; return showFullText ? 'Stop' : null; } // Show cooldown if this button caused it From 8261c0292e7210a26b027a06eed7b729adf5cfaa Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Sun, 15 Mar 2026 20:33:32 -0400 Subject: [PATCH 44/57] ### New Features - Auto-stop after idle: auto-ping now automatically stops after 30 minutes of continuous skipped pings (no movement), saving battery and radio activity - New "Auto-Stop After Idle" toggle in Settings (default: ON), located under Min Ping Distance --- lib/models/user_preferences.dart | 12 ++++++++- lib/providers/app_state_provider.dart | 35 +++++++++++++++++++++++++++ lib/screens/settings_screen.dart | 11 +++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index b37b57a..331519b 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -79,6 +79,9 @@ class UserPreferences { /// Minimum ping distance in meters (25m floor, user can increase) final int minPingDistanceMeters; + /// Auto-stop auto-ping after 30 minutes of idle (no movement) + final bool autoStopAfterIdle; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -106,6 +109,7 @@ class UserPreferences { this.discDropEnabled = false, this.deleteChannelOnDisconnect = true, this.minPingDistanceMeters = 25, + this.autoStopAfterIdle = true, }); /// Create from JSON (for persistence) @@ -137,6 +141,7 @@ class UserPreferences { discDropEnabled: (json['discDropEnabled'] as bool?) ?? false, deleteChannelOnDisconnect: (json['deleteChannelOnDisconnect'] as bool?) ?? true, minPingDistanceMeters: (json['minPingDistanceMeters'] as int?) ?? 25, + autoStopAfterIdle: (json['autoStopAfterIdle'] as bool?) ?? true, ); } @@ -169,6 +174,7 @@ class UserPreferences { 'discDropEnabled': discDropEnabled, 'deleteChannelOnDisconnect': deleteChannelOnDisconnect, 'minPingDistanceMeters': minPingDistanceMeters, + 'autoStopAfterIdle': autoStopAfterIdle, }; } @@ -200,6 +206,7 @@ class UserPreferences { bool? discDropEnabled, bool? deleteChannelOnDisconnect, int? minPingDistanceMeters, + bool? autoStopAfterIdle, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -228,6 +235,7 @@ class UserPreferences { discDropEnabled: discDropEnabled ?? this.discDropEnabled, deleteChannelOnDisconnect: deleteChannelOnDisconnect ?? this.deleteChannelOnDisconnect, minPingDistanceMeters: minPingDistanceMeters ?? this.minPingDistanceMeters, + autoStopAfterIdle: autoStopAfterIdle ?? this.autoStopAfterIdle, ); } @@ -284,7 +292,8 @@ class UserPreferences { other.anonymousMode == anonymousMode && other.discDropEnabled == discDropEnabled && other.deleteChannelOnDisconnect == deleteChannelOnDisconnect && - other.minPingDistanceMeters == minPingDistanceMeters; + other.minPingDistanceMeters == minPingDistanceMeters && + other.autoStopAfterIdle == autoStopAfterIdle; } @override @@ -315,6 +324,7 @@ class UserPreferences { discDropEnabled, deleteChannelOnDisconnect, minPingDistanceMeters, + autoStopAfterIdle, ]); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index bf8b5e5..15d04a8 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -139,6 +139,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { PingStats _pingStats = const PingStats(); bool _autoPingEnabled = false; AutoMode _autoMode = AutoMode.active; + DateTime? _idleAutoStopReference; + static const Duration _autoStopIdleTimeout = Duration(minutes: 30); bool _isPingSending = false; // True immediately when ping button clicked int _queueSize = 0; int? _currentNoiseFloor; @@ -1346,6 +1348,20 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Wire up auto ping scheduled callback for countdown display _pingService!.onAutoPingScheduled = (intervalMs, skipReason) { _autoPingTimer.startWithSkipReason(intervalMs, skipReason); + + // Track idle time for auto-stop + if (skipReason != null) { + // Ping was skipped — check if idle too long + if (_preferences.autoStopAfterIdle && _idleAutoStopReference != null) { + final elapsed = DateTime.now().difference(_idleAutoStopReference!); + if (elapsed >= _autoStopIdleTimeout) { + _triggerIdleAutoStop(); + } + } + } else { + // Successful ping — reset idle reference + _idleAutoStopReference = DateTime.now(); + } }; // Wire up discovery ping callback - fires immediately (like onTxPing) @@ -1513,6 +1529,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update local state _autoPingEnabled = false; + _idleAutoStopReference = null; debugLog('[APP] Pending disable cleanup complete, cooldown running'); notifyListeners(); @@ -2001,6 +2018,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _cooldownTimer.stop(); if (_autoPingEnabled) { _autoPingEnabled = false; + _idleAutoStopReference = null; debugLog('[AUTO] Auto-ping disabled due to BLE disconnect'); } @@ -2064,6 +2082,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _rxWindowTimer.stop(); _cooldownTimer.stop(); _autoPingEnabled = false; + _idleAutoStopReference = null; // Stop heartbeat _apiService.disableHeartbeat(); @@ -2252,6 +2271,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (_autoPingEnabled) { await _pingService?.forceDisableAutoPing(); _autoPingEnabled = false; + _idleAutoStopReference = null; } // End noise floor session on disconnect @@ -2451,6 +2471,18 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { notifyListeners(); } + /// Auto-stop auto-ping after prolonged idle (no movement) + void _triggerIdleAutoStop() { + if (!_autoPingEnabled) return; + final elapsed = _idleAutoStopReference != null + ? DateTime.now().difference(_idleAutoStopReference!).inMinutes + : 30; + debugLog('[AUTO] Auto-stop triggered: idle for $elapsed minutes'); + logError('Auto-ping stopped: no movement for 30 minutes', severity: ErrorSeverity.warning, autoSwitch: false); + _idleAutoStopReference = null; + toggleAutoPing(_autoMode); + } + /// Toggle auto-ping mode (Active, Passive, Hybrid, or Trace) /// Returns false if blocked by cooldown (Active/Hybrid/Trace Mode only - Passive Mode ignores cooldown) Future toggleAutoPing(AutoMode mode) async { @@ -2504,6 +2536,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _apiService.disableHeartbeat(); _autoPingEnabled = false; + _idleAutoStopReference = null; // Start 5-second shared cooldown for TX modes (Active/Hybrid), not Passive Mode // Passive Mode is listening only, no cooldown needed @@ -2573,6 +2606,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Reference: state.rxTracking.isWardriving = true in wardrive.js _rxLogger?.startWardriving(); _autoPingEnabled = true; + _idleAutoStopReference = DateTime.now(); // Start noise floor session for graph tracking final sessionLabel = isPassive ? 'passive' : isHybrid ? 'hybrid' : isTargeted ? 'targeted' : 'active'; @@ -3020,6 +3054,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // 9. Update state _autoPingEnabled = false; + _idleAutoStopReference = null; debugLog('[APP] Auto-ping mode stopped gracefully'); notifyListeners(); } diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 9a5b390..ea3b01c 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -166,6 +166,17 @@ class _SettingsScreenState extends State { onTap: isAutoMode ? null : () => _showDistanceSelector(context, appState), ), + // Auto-Stop After Idle Toggle + SwitchListTile( + secondary: const Icon(Icons.timer_off), + title: const Text('Auto-Stop After Idle'), + subtitle: const Text('Stops auto-ping after 30 min without movement'), + value: prefs.autoStopAfterIdle, + onChanged: isAutoMode ? null : (value) { + appState.updatePreferences(prefs.copyWith(autoStopAfterIdle: value)); + }, + ), + // Hybrid Mode Toggle SwitchListTile( secondary: const Icon(Icons.compare_arrows), From 980d1fb26f3ffe03cfdec77bce57af5d542c6753 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Mon, 16 Mar 2026 07:24:19 -0400 Subject: [PATCH 45/57] fix trace bytes --- lib/providers/app_state_provider.dart | 29 ++++++- lib/screens/log_screen.dart | 20 +++-- lib/screens/settings_screen.dart | 104 +++++++++++++++++++++-- lib/services/meshcore/connection.dart | 17 +++- lib/services/meshcore/trace_tracker.dart | 1 - lib/services/ping_service.dart | 20 +++-- lib/widgets/ping_controls.dart | 4 +- lib/widgets/repeater_id_chip.dart | 2 + 8 files changed, 168 insertions(+), 29 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 15d04a8..fc7f2a1 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -264,6 +264,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { int? _originalPathHashMode; // Device's mode BEFORE we changed it (from DeviceInfo) bool _userChangedPathMode = false; // True if user manually changed hopBytes while connected int _hopBytes = 1; // Runtime-only: current hop byte size (read from device, not persisted) + int _traceHopBytes = 1; // Runtime-only: trace byte size (1, 2, or 4 — bitshift encoding) // Noise floor session tracking (for graph feature) NoiseFloorSession? _currentNoiseFloorSession; @@ -429,6 +430,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get enforceHopBytes => _apiService.enforceHopBytes; int get hopBytes => _hopBytes; int get effectiveHopBytes => enforceHopBytes ? _apiService.apiHopBytes : _hopBytes; + int get traceHopBytes => _traceHopBytes; bool get supportsMultiBytePaths => _originalPathHashMode != null; // Offline mode @@ -1192,6 +1194,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { audioService: _audioService, disableRssiFilter: _preferences.disableRssiFilter, hopBytes: effectiveHopBytes, + traceHopBytes: _traceHopBytes, shouldIgnoreRepeater: (String repeaterId) { final prefs = _preferences; if (prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null) { @@ -1893,9 +1896,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (_originalPathHashMode != null) { final deviceHopBytes = _originalPathHashMode! + 1; _hopBytes = deviceHopBytes; - debugLog('[PATH] Read device path mode: $deviceHopBytes-byte'); + // Map TX bytes to trace bytes (3-byte traces not possible, use 4) + _traceHopBytes = deviceHopBytes == 3 ? 4 : deviceHopBytes; + _pingService?.traceHopBytes = _traceHopBytes; + debugLog('[PATH] Read device path mode: $deviceHopBytes-byte (trace: $_traceHopBytes-byte)'); } else { _hopBytes = 1; + _traceHopBytes = 1; } final effective = effectiveHopBytes; @@ -1907,7 +1914,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { try { await _meshCoreConnection!.setPathHashMode(effective - 1); _hopBytes = effective; // Update runtime state to reflect new mode - debugLog('[PATH] Set path hash mode: device was $deviceHopBytes-byte, now $effective-byte'); + _traceHopBytes = effective == 3 ? 4 : effective; + _pingService?.traceHopBytes = _traceHopBytes; + debugLog('[PATH] Set path hash mode: device was $deviceHopBytes-byte, now $effective-byte (trace: $_traceHopBytes-byte)'); // Show warning popup if changing from 1-byte to multi-byte if (deviceMode == 0 && effective > 1) { @@ -1976,9 +1985,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _hopBytes = newHopBytes; _userChangedPathMode = true; _pingService?.hopBytes = newHopBytes; + // Auto-map trace bytes when TX bytes change (3→4, others stay same) + _traceHopBytes = newHopBytes == 3 ? 4 : newHopBytes; + _pingService?.traceHopBytes = _traceHopBytes; final mode = newHopBytes - 1; // Convert 1/2/3 → mode 0/1/2 _meshCoreConnection?.setPathHashMode(mode); - debugLog('[PATH] User changed path mode to $newHopBytes-byte (sent to radio)'); + debugLog('[PATH] User changed path mode to $newHopBytes-byte (trace: $_traceHopBytes-byte, sent to radio)'); notifyListeners(); } @@ -1995,6 +2007,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + /// Set trace hop bytes (called from settings UI). Valid values: 1, 2, 4. + void setTraceHopBytes(int value) { + if (value != 1 && value != 2 && value != 4) return; + if (value == _traceHopBytes) return; + _traceHopBytes = value; + _pingService?.traceHopBytes = value; + debugLog('[TRACE] User changed trace bytes to $value'); + notifyListeners(); + } + /// Pending path hash warning data (for UI to show dialog) ({int hopBytes, String reason})? _pendingPathHashWarning; ({int hopBytes, String reason})? get pendingPathHashWarning => _pendingPathHashWarning; @@ -2380,6 +2402,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _originalPathHashMode = null; _userChangedPathMode = false; _hopBytes = 1; + _traceHopBytes = 1; // Clear regional channels (keeps only Public) and scope ChannelService.clearRegionalChannels(); diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index c8ab642..e172340 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -451,7 +451,7 @@ class _TxLogTab extends StatelessWidget { child: Row( children: [ SizedBox( - width: 50, + width: 60, child: Text( 'Node', style: TextStyle( @@ -543,7 +543,7 @@ class _TxLogTab extends StatelessWidget { child: Row( children: [ // Repeater ID - RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 11, width: 50), + RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 11, width: 60), // SNR Expanded( child: Center( @@ -713,7 +713,7 @@ class _RxLogTab extends StatelessWidget { child: Row( children: [ SizedBox( - width: 50, + width: 60, child: Text( 'Node', style: TextStyle( @@ -757,7 +757,7 @@ class _RxLogTab extends StatelessWidget { child: Row( children: [ // Repeater ID - RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 11, width: 50), + RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 11, width: 60), // SNR Expanded( child: Center( @@ -923,7 +923,7 @@ class _DiscLogTab extends StatelessWidget { child: Row( children: [ SizedBox( - width: 50, + width: 70, child: Text( 'Node', style: TextStyle( @@ -1034,10 +1034,12 @@ class _DiscLogTab extends StatelessWidget { children: [ // Node ID with type SizedBox( - width: 50, + width: 70, child: Row( children: [ - RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 11), + Flexible( + child: RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 11), + ), Text( node.nodeTypeLabel, style: const TextStyle( @@ -1232,7 +1234,7 @@ class _TraceLogTab extends StatelessWidget { child: Row( children: [ SizedBox( - width: 50, + width: 70, child: Text( 'Node', style: TextStyle( @@ -1348,7 +1350,7 @@ class _TraceLogTab extends StatelessWidget { child: Row( children: [ SizedBox( - width: 50, + width: 70, child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 11), ), Expanded( diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index ea3b01c..873ad1d 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -340,12 +340,12 @@ class _SettingsScreenState extends State { const Divider(), _buildSectionHeader(context, 'Radio Settings'), - // Path Bytes Setting + // TX Bytes Setting ListTile( leading: const Icon(Icons.linear_scale), title: Row( children: [ - const Flexible(child: Text('Path Bytes', overflow: TextOverflow.ellipsis)), + const Flexible(child: Text('TX Bytes', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), GestureDetector( onTap: () => _showHopBytesInfo(context), @@ -372,7 +372,7 @@ class _SettingsScreenState extends State { 'Connect to radio to configure', style: TextStyle(color: Colors.amber), ) - : const Text('Repeater ID size in path hops'), + : const Text('Repeater ID size in TX/RX path hops'), trailing: DropdownButton( value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, underline: const SizedBox(), @@ -389,6 +389,50 @@ class _SettingsScreenState extends State { ), ), + // Trace Bytes Setting + ListTile( + leading: const Icon(Icons.gps_fixed), + title: Row( + children: [ + const Flexible(child: Text('Trace Bytes', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showTraceBytesInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + subtitle: !appState.isConnected + ? const Text( + 'Connect to radio to configure', + style: TextStyle(color: Colors.amber), + ) + : (appState.isConnected && !appState.supportsMultiBytePaths) + ? const Text( + 'Firmware 1.14+ required', + style: TextStyle(color: Colors.amber), + ) + : const Text('Repeater ID size in trace path'), + trailing: DropdownButton( + value: appState.traceHopBytes, + underline: const SizedBox(), + items: const [ + DropdownMenuItem(value: 1, child: Text('1')), + DropdownMenuItem(value: 2, child: Text('2')), + DropdownMenuItem(value: 4, child: Text('4')), + ], + onChanged: (!appState.isConnected || isAutoMode || !appState.supportsMultiBytePaths) + ? null + : (value) { + if (value != null) appState.setTraceHopBytes(value); + }, + ), + ), + // Background Mode - for "Always" location permission (iOS and Android) if (!kIsWeb) ...[ const Divider(), @@ -1142,7 +1186,7 @@ class _SettingsScreenState extends State { children: [ Icon(Icons.linear_scale, size: 24), SizedBox(width: 8), - Text('Path Bytes'), + Text('TX Bytes'), ], ), content: const Column( @@ -1150,7 +1194,7 @@ class _SettingsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Controls how many bytes are used to identify each repeater in the packet path. ' + 'Controls how many bytes are used to identify each repeater in TX/RX packet paths. ' 'More bytes = more unique IDs, reducing collisions in large networks.', style: TextStyle(fontSize: 14), ), @@ -1179,6 +1223,56 @@ class _SettingsScreenState extends State { ); } + void _showTraceBytesInfo(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.gps_fixed, size: 24), + SizedBox(width: 8), + Text('Trace Bytes'), + ], + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Controls how many bytes are used for the repeater ID in trace path requests. ' + 'This is separate from TX Bytes because traces use a different encoding.', + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 12), + Text( + 'TX/RX uses a simple counter:\n' + '\u2022 Mode 0 \u2192 1 byte\n' + '\u2022 Mode 1 \u2192 2 bytes\n' + '\u2022 Mode 2 \u2192 3 bytes\n\n' + 'Trace uses bitshift encoding:\n' + '\u2022 Mode 0 \u2192 1 byte\n' + '\u2022 Mode 1 \u2192 2 bytes\n' + '\u2022 Mode 2 \u2192 4 bytes', + style: TextStyle(fontSize: 13), + ), + SizedBox(height: 12), + Text( + '3-byte traces are not supported by the MeshCore protocol. ' + 'When your region uses 3-byte TX paths, set Trace Bytes to 4.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Got it'), + ), + ], + ), + ); + } + void _showIntervalSelector(BuildContext context, AppStateProvider appState) { final minInterval = appState.minModeInterval; var currentInterval = appState.preferences.autoPingInterval; diff --git a/lib/services/meshcore/connection.dart b/lib/services/meshcore/connection.dart index fa97a16..07c0810 100644 --- a/lib/services/meshcore/connection.dart +++ b/lib/services/meshcore/connection.dart @@ -981,20 +981,31 @@ class MeshCoreConnection { /// Send trace path to a specific repeater (targeted ping / zero-hop trace) /// Returns the 4-byte tag used for matching the response - Future sendTracePath(Uint8List repeaterIdBytes) async { + /// [hopBytes] controls trace ID size: 1, 2, or 4 bytes (bitshift encoding) + Future sendTracePath(Uint8List repeaterIdBytes, {int hopBytes = 1}) async { final random = Random.secure(); final tag = Uint8List.fromList([ random.nextInt(256), random.nextInt(256), random.nextInt(256), random.nextInt(256), ]); - debugLog('[CONN] Sending trace to ${repeaterIdBytes.map((b) => b.toRadixString(16).padLeft(2, "0")).join("")}'); + // Trace uses bitshift encoding: actual_bytes = 1 << path_sz + // 1 → path_sz=0, 2 → path_sz=1, 4 → path_sz=2 + final int pathSz; + switch (hopBytes) { + case 4: pathSz = 2; break; + case 2: pathSz = 1; break; + default: pathSz = 0; break; + } + final int flags = pathSz & 0x03; + + debugLog('[CONN] Sending trace to ${repeaterIdBytes.map((b) => b.toRadixString(16).padLeft(2, "0")).join("")} (traceBytes=$hopBytes, path_sz=$pathSz)'); final data = BufferWriter(); data.writeByte(CommandCodes.sendTracePath); // 0x24 data.writeBytes(tag); // 4-byte tag data.writeUInt32LE(0); // auth_code = 0 - data.writeByte(0); // flags = 0 + data.writeByte(flags); // flags with path_sz in bits 0-1 data.writeBytes(repeaterIdBytes); // target repeater ID await _sendToRadio(data); return tag; diff --git a/lib/services/meshcore/trace_tracker.dart b/lib/services/meshcore/trace_tracker.dart index 09c1358..ad7b529 100644 --- a/lib/services/meshcore/trace_tracker.dart +++ b/lib/services/meshcore/trace_tracker.dart @@ -49,7 +49,6 @@ class TraceTracker { void startTracking({ required Uint8List tag, required String targetRepeaterId, - int hopBytes = 1, Duration windowDuration = const Duration(seconds: 7), }) { debugLog('[TRACE] Starting trace tracking for repeater $targetRepeaterId'); diff --git a/lib/services/ping_service.dart b/lib/services/ping_service.dart index e235392..d782282 100644 --- a/lib/services/ping_service.dart +++ b/lib/services/ping_service.dart @@ -70,9 +70,15 @@ class PingService { /// Number of bytes per hop in path hash (1, 2, or 3). Passed to DiscTracker for repeater ID length. int _hopBytes; + /// Number of bytes for trace path IDs (1, 2, or 4). Uses bitshift encoding, separate from TX. + int _traceHopBytes; + /// Update hop bytes at runtime (e.g. when user changes path mode while connected) set hopBytes(int value) => _hopBytes = value; + /// Update trace hop bytes at runtime (e.g. when user changes trace byte setting) + set traceHopBytes(int value) => _traceHopBytes = value; + /// When true, skip RSSI carpeater check in DiscTracker (user setting) bool disableRssiFilter; @@ -197,6 +203,7 @@ class PingService { this.shouldIgnoreRepeater, this.disableRssiFilter = false, int hopBytes = 1, + int traceHopBytes = 1, }) : _gpsService = gpsService, _connection = connection, _apiQueue = apiQueue, @@ -208,7 +215,8 @@ class PingService { _deviceId = deviceId, _txTracker = txTracker, _audioService = audioService, - _hopBytes = hopBytes; + _hopBytes = hopBytes, + _traceHopBytes = traceHopBytes; /// Get current ping statistics PingStats get stats => _stats; @@ -1410,20 +1418,20 @@ class PingService { // Play transmit sound _audioService?.playTransmitSound(); - // Convert hex repeater ID to bytes - final repeaterIdBytes = Uint8List(_hopBytes); - for (int i = 0; i < _hopBytes && i * 2 + 2 <= targetId.length; i++) { + // Convert hex repeater ID to bytes (trace uses separate byte size: 1, 2, or 4) + final traceBytes = _traceHopBytes; + final repeaterIdBytes = Uint8List(traceBytes); + for (int i = 0; i < traceBytes && i * 2 + 2 <= targetId.length; i++) { repeaterIdBytes[i] = int.parse(targetId.substring(i * 2, i * 2 + 2), radix: 16); } // Send trace path and get tag - final tag = await _connection.sendTracePath(repeaterIdBytes); + final tag = await _connection.sendTracePath(repeaterIdBytes, hopBytes: traceBytes); // Start tracking with the tag _traceTracker?.startTracking( tag: tag, targetRepeaterId: targetId, - hopBytes: _hopBytes, windowDuration: _rxListeningWindow, ); diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index d0046da..42915f2 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -487,7 +487,7 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { Widget build(BuildContext context) { final appState = context.watch(); final isTargetedRunning = appState.isTargetedModeRunning; - final maxLen = appState.effectiveHopBytes * 2; + final maxLen = appState.traceHopBytes * 2; final colorScheme = Theme.of(context).colorScheme; // Determine if the start button should be enabled @@ -597,7 +597,7 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { : colorScheme.onSurface, ), decoration: InputDecoration( - hintText: 'e.g. ${maxLen == 2 ? '4E' : maxLen == 4 ? '4E7A' : '4E7A3B'}', + hintText: 'e.g. ${maxLen == 2 ? '4E' : maxLen == 4 ? '4E7A' : maxLen == 8 ? '4E7A3B00' : '4E7A3B'}', hintStyle: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), diff --git a/lib/widgets/repeater_id_chip.dart b/lib/widgets/repeater_id_chip.dart index 6d25d4d..0088da5 100644 --- a/lib/widgets/repeater_id_chip.dart +++ b/lib/widgets/repeater_id_chip.dart @@ -44,6 +44,8 @@ class RepeaterIdChip extends StatelessWidget { children: [ Text( repeaterId, + softWrap: false, + overflow: TextOverflow.clip, style: TextStyle( fontSize: effectiveFontSize, fontWeight: FontWeight.w600, From 9e301b5ed02389a3308dc5fd0cd42d00535d1a83 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Mon, 16 Mar 2026 09:41:05 -0400 Subject: [PATCH 46/57] Added Repeater Picker dropdown for traces --- lib/models/noise_floor_session.dart | 2 +- lib/providers/app_state_provider.dart | 90 +++++++ lib/widgets/ping_controls.dart | 41 +++ lib/widgets/repeater_picker_sheet.dart | 341 +++++++++++++++++++++++++ 4 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 lib/widgets/repeater_picker_sheet.dart diff --git a/lib/models/noise_floor_session.dart b/lib/models/noise_floor_session.dart index a1f1fe9..47f2627 100644 --- a/lib/models/noise_floor_session.dart +++ b/lib/models/noise_floor_session.dart @@ -106,7 +106,7 @@ class PingEventMarker extends HiveObject { PingEventType.discSuccess => Colors.purple, PingEventType.discFail => Colors.grey, PingEventType.traceSuccess => Colors.cyan, - PingEventType.traceFail => Colors.red, + PingEventType.traceFail => Colors.grey, }; /// Get a display label for this event type diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index fc7f2a1..98b5170 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -236,6 +236,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { Timer? _reconnectTimeoutTimer; Timer? _restoreAutoPingTimer; Timer? _offlineAutoSaveTimer; + Timer? _zoneRefreshTimer; bool _autoPingWasEnabled = false; AutoMode _autoModeBeforeReconnect = AutoMode.active; int _reconnectRestoreGeneration = 0; @@ -940,6 +941,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { notifyListeners(); } + // Sync zone capacity display with auth result + _syncZoneCapacityFromAuth(result); + return result; } @@ -1029,6 +1033,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { notifyListeners(); } + // Sync zone capacity display with auth result + _syncZoneCapacityFromAuth(registerResult); + return registerResult; }; } else { @@ -1585,6 +1592,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } else { debugLog('[CONN] Connected with limited access'); } + + // Start periodic zone refresh to keep slot counts current + if (!_preferences.offlineMode) { + _startZoneRefreshTimer(); + } } else { // No API session - offline mode or auth skipped debugLog('[CONN] Connected without API session (offline mode)'); @@ -1986,8 +1998,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _userChangedPathMode = true; _pingService?.hopBytes = newHopBytes; // Auto-map trace bytes when TX bytes change (3→4, others stay same) + final oldTraceHopBytes = _traceHopBytes; _traceHopBytes = newHopBytes == 3 ? 4 : newHopBytes; _pingService?.traceHopBytes = _traceHopBytes; + // Clear target repeater if trace bytes changed — old hex ID has wrong byte length + if (_traceHopBytes != oldTraceHopBytes) { + _targetRepeaterId = null; + } final mode = newHopBytes - 1; // Convert 1/2/3 → mode 0/1/2 _meshCoreConnection?.setPathHashMode(mode); debugLog('[PATH] User changed path mode to $newHopBytes-byte (trace: $_traceHopBytes-byte, sent to radio)'); @@ -2013,6 +2030,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (value == _traceHopBytes) return; _traceHopBytes = value; _pingService?.traceHopBytes = value; + // Clear target repeater — old hex ID has wrong byte length + _targetRepeaterId = null; debugLog('[TRACE] User changed trace bytes to $value'); notifyListeners(); } @@ -2034,6 +2053,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _apiService.disableHeartbeat(); debugLog('[CONN] Heartbeat disabled due to BLE disconnect'); + // Stop zone refresh timer + _stopZoneRefreshTimer(); + // Stop auto-ping timers _autoPingTimer.stop(); _rxWindowTimer.stop(); @@ -2289,6 +2311,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Disable heartbeat immediately on disconnect _apiService.disableHeartbeat(); + // Stop zone refresh timer + _stopZoneRefreshTimer(); + // Stop auto-ping if running (before releasing session) if (_autoPingEnabled) { await _pingService?.forceDisableAutoPing(); @@ -2936,6 +2961,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Auth type: $_authType'); notifyListeners(); } + _syncZoneCapacityFromAuth(result); } else if (result == null) { // API unreachable (null = network/timeout error) debugError('[APP] API unreachable - network error'); @@ -3002,6 +3028,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Auth type: $_authType'); notifyListeners(); } + _syncZoneCapacityFromAuth(registerResult); result = registerResult; } @@ -3965,6 +3992,68 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + /// Sync zone capacity display with auth result. + /// The /status API (pre-connection) and /auth API (during connection) can + /// return different capacity views. This keeps the connection screen's slot + /// display consistent with the map tab's txAllowed flag. + void _syncZoneCapacityFromAuth(Map authResult) { + if (_currentZone == null) return; + + // If auth response includes slot data, use it directly (forward-compatible) + if (authResult.containsKey('slots_available')) { + _currentZone!['slots_available'] = authResult['slots_available']; + debugLog('[CAPACITY] Updated slots_available from auth: ${authResult['slots_available']}'); + } + if (authResult.containsKey('slots_max')) { + _currentZone!['slots_max'] = authResult['slots_max']; + debugLog('[CAPACITY] Updated slots_max from auth: ${authResult['slots_max']}'); + } + + // Sync at_capacity with tx_allowed + final authTxAllowed = authResult['tx_allowed'] == true; + _currentZone!['at_capacity'] = !authTxAllowed; + + // If auth says TX not allowed and server didn't provide slot data, set slots to 0 + if (!authTxAllowed && !authResult.containsKey('slots_available')) { + _currentZone!['slots_available'] = 0; + debugLog('[CAPACITY] Zone at TX capacity per auth, set slots_available=0'); + } + + // If auth says TX allowed and we have slot data but server didn't provide updated count, + // decrement by 1 (we just took a slot) + if (authTxAllowed && !authResult.containsKey('slots_available')) { + final available = _currentZone!['slots_available'] as int?; + if (available != null && available > 0) { + _currentZone!['slots_available'] = available - 1; + debugLog('[CAPACITY] Took a slot, slots_available=${available - 1}'); + } + } + + notifyListeners(); + } + + /// Start periodic zone status refresh while connected. + /// Keeps slot counts and capacity status fresh during a session. + void _startZoneRefreshTimer() { + _zoneRefreshTimer?.cancel(); + _zoneRefreshTimer = Timer.periodic(const Duration(seconds: 60), (_) async { + if (!isConnected || _preferences.offlineMode) { + _zoneRefreshTimer?.cancel(); + _zoneRefreshTimer = null; + return; + } + debugLog('[CAPACITY] Periodic zone refresh'); + await checkZoneStatus(); + }); + debugLog('[CAPACITY] Started 60s zone refresh timer'); + } + + /// Stop zone status refresh timer. + void _stopZoneRefreshTimer() { + _zoneRefreshTimer?.cancel(); + _zoneRefreshTimer = null; + } + /// Fetch repeaters for a zone (called when zone is discovered) /// Only fetches once per IATA code to avoid redundant network requests Future _fetchRepeatersForZone(String iata) async { @@ -4758,6 +4847,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _reconnectTimeoutTimer?.cancel(); _restoreAutoPingTimer?.cancel(); _offlineAutoSaveTimer?.cancel(); + _zoneRefreshTimer?.cancel(); _tileRefreshTimer?.cancel(); _unifiedRxHandler?.dispose(); _meshCoreConnection?.dispose(); diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index 42915f2..d1e6695 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -6,6 +6,7 @@ import '../providers/app_state_provider.dart'; import '../services/ping_service.dart'; import '../utils/debug_logger_io.dart'; import 'offline_mode_toggle.dart'; +import 'repeater_picker_sheet.dart'; /// Modern ping control panel with icon-based buttons and animated status class PingControls extends StatelessWidget { @@ -483,6 +484,20 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { super.dispose(); } + Future _showRepeaterPicker() async { + final appState = context.read(); + final repeater = await showRepeaterPicker(context); + if (repeater == null || !mounted) return; + + final maxLen = appState.traceHopBytes * 2; + final trimmed = repeater.hexId.length >= maxLen + ? repeater.hexId.substring(0, maxLen).toUpperCase() + : repeater.hexId.toUpperCase(); + _controller.text = trimmed; + appState.setTargetRepeaterId(trimmed); + setState(() {}); + } + @override Widget build(BuildContext context) { final appState = context.watch(); @@ -490,6 +505,11 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { final maxLen = appState.traceHopBytes * 2; final colorScheme = Theme.of(context).colorScheme; + // Sync controller when provider clears target (e.g. trace bytes changed) + if (appState.targetRepeaterId == null && _controller.text.isNotEmpty) { + _controller.clear(); + } + // Determine if the start button should be enabled final hexText = _controller.text.trim(); final isValidHex = hexText.isNotEmpty && @@ -619,6 +639,27 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { }, ), ), + const SizedBox(width: 6), + // Choose repeater button + SizedBox( + width: 32, + height: 32, + child: IconButton( + icon: Icon( + Icons.list, + size: 18, + color: (!isTargetedRunning && appState.repeaters.isNotEmpty) + ? effectiveColor + : colorScheme.onSurfaceVariant.withValues(alpha: 0.3), + ), + onPressed: (!isTargetedRunning && appState.repeaters.isNotEmpty) + ? _showRepeaterPicker + : null, + padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + tooltip: 'Choose repeater', + ), + ), ], ), ); diff --git a/lib/widgets/repeater_picker_sheet.dart b/lib/widgets/repeater_picker_sheet.dart new file mode 100644 index 0000000..a10fa2d --- /dev/null +++ b/lib/widgets/repeater_picker_sheet.dart @@ -0,0 +1,341 @@ +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:provider/provider.dart'; + +import '../models/repeater.dart'; +import '../providers/app_state_provider.dart'; +import '../services/gps_service.dart'; +import '../utils/distance_formatter.dart'; + +/// Show a bottom sheet repeater picker and return the selected repeater. +Future showRepeaterPicker(BuildContext context) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + backgroundColor: Theme.of(context).colorScheme.surface, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => DraggableScrollableSheet( + initialChildSize: 0.95, + minChildSize: 0.4, + maxChildSize: 0.95, + expand: false, + builder: (context, scrollController) => _RepeaterPickerBody( + scrollController: scrollController, + ), + ), + ); +} + +class _RepeaterPickerBody extends StatefulWidget { + final ScrollController scrollController; + + const _RepeaterPickerBody({required this.scrollController}); + + @override + State<_RepeaterPickerBody> createState() => _RepeaterPickerBodyState(); +} + +class _RepeaterPickerBodyState extends State<_RepeaterPickerBody> { + final _searchController = TextEditingController(); + String _query = ''; + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + List _filterAndSort(List repeaters, Position? position) { + List filtered; + if (_query.isNotEmpty) { + final q = _query.toLowerCase(); + filtered = repeaters + .where((r) => + r.name.toLowerCase().contains(q) || + r.hexId.toLowerCase().startsWith(q)) + .toList(); + } else { + filtered = List.of(repeaters); + } + + // Sort: active first, then by distance (if GPS), then alphabetically + filtered.sort((a, b) { + // Active first + if (a.isActive != b.isActive) return a.isActive ? -1 : 1; + // By distance if GPS available + if (position != null) { + final distA = GpsService.distanceBetween( + position.latitude, position.longitude, a.lat, a.lon, + ); + final distB = GpsService.distanceBetween( + position.latitude, position.longitude, b.lat, b.lon, + ); + return distA.compareTo(distB); + } + // Alphabetically + return a.name.toLowerCase().compareTo(b.name.toLowerCase()); + }); + + return filtered; + } + + @override + Widget build(BuildContext context) { + final appState = context.watch(); + final repeaters = appState.repeaters; + final position = appState.currentPosition; + final isImperial = appState.preferences.isImperial; + final colorScheme = Theme.of(context).colorScheme; + + final filtered = _filterAndSort(repeaters, position); + + return Column( + children: [ + // Drag handle + Padding( + padding: const EdgeInsets.only(top: 8, bottom: 4), + child: Container( + width: 36, + height: 4, + decoration: BoxDecoration( + color: colorScheme.onSurfaceVariant.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(2), + ), + ), + ), + // Header + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Icon(Icons.cell_tower, size: 20, color: colorScheme.primary), + const SizedBox(width: 8), + Text( + 'Select Repeater', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w600, + color: colorScheme.onSurface, + ), + ), + const Spacer(), + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + visualDensity: VisualDensity.compact, + ), + ], + ), + ), + // Search field + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + hintText: 'Search by name or hex ID...', + prefixIcon: const Icon(Icons.search, size: 20), + suffixIcon: _query.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear, size: 18), + onPressed: () { + _searchController.clear(); + setState(() => _query = ''); + }, + ) + : null, + isDense: true, + contentPadding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onChanged: (value) => setState(() => _query = value), + ), + ), + // Count label + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'Showing ${filtered.length} of ${repeaters.length} repeaters', + style: TextStyle( + fontSize: 12, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + ), + const Divider(height: 1), + // List + Expanded( + child: filtered.isEmpty + ? Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: Text( + repeaters.isEmpty + ? 'No repeaters available' + : 'No repeaters match your search', + style: TextStyle( + fontSize: 14, + fontStyle: FontStyle.italic, + color: colorScheme.onSurfaceVariant, + ), + ), + ), + ) + : ListView.builder( + controller: widget.scrollController, + itemCount: filtered.length, + itemBuilder: (context, index) { + final r = filtered[index]; + return _RepeaterTile( + repeater: r, + position: position, + isImperial: isImperial, + onTap: () => Navigator.pop(context, r), + ); + }, + ), + ), + ], + ); + } +} + +class _RepeaterTile extends StatelessWidget { + final Repeater repeater; + final Position? position; + final bool isImperial; + final VoidCallback onTap; + + const _RepeaterTile({ + required this.repeater, + required this.position, + required this.isImperial, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + final isActive = repeater.isActive; + final badgeColor = isActive ? Colors.green : Colors.grey; + + // Distance text + String? distanceText; + if (position != null) { + final meters = GpsService.distanceBetween( + position!.latitude, position!.longitude, repeater.lat, repeater.lon, + ); + if (meters < 1000) { + distanceText = formatMeters(meters, isImperial: isImperial); + } else { + distanceText = + formatKilometers(meters / 1000, isImperial: isImperial); + } + } + + // Always show 4-byte (8-char) hex ID for identification + final displayHex = repeater.hexId.length >= 8 + ? repeater.hexId.substring(0, 8).toUpperCase() + : repeater.hexId.toUpperCase(); + + return InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + child: Row( + children: [ + // Hex badge + Container( + constraints: const BoxConstraints(minWidth: 28), + height: 28, + padding: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + color: badgeColor, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Text( + displayHex, + style: TextStyle( + fontSize: displayHex.length > 4 ? 8 : 10, + fontWeight: FontWeight.bold, + color: Colors.white, + fontFamily: 'monospace', + ), + ), + ), + const SizedBox(width: 12), + // Name + distance + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + repeater.name, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: colorScheme.onSurface, + ), + overflow: TextOverflow.ellipsis, + ), + if (distanceText != null) + Padding( + padding: const EdgeInsets.only(top: 2), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.near_me, + size: 10, + color: colorScheme.onSurfaceVariant, + ), + const SizedBox(width: 3), + Text( + distanceText, + style: TextStyle( + fontSize: 11, + color: colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(width: 8), + // Active/Stale chip + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + decoration: BoxDecoration( + color: badgeColor.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(10), + border: + Border.all(color: badgeColor.withValues(alpha: 0.4)), + ), + child: Text( + isActive ? 'Active' : 'Stale', + style: TextStyle( + fontSize: 11, + color: badgeColor, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ); + } +} From 904c1dd8d5a0e3060594316aeb02d8aef550c3d9 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Mon, 16 Mar 2026 20:55:06 -0400 Subject: [PATCH 47/57] Final fixes for trace mode --- lib/models/noise_floor_session.dart | 2 +- lib/widgets/map_widget.dart | 16 ++++++++-------- lib/widgets/noise_floor_chart.dart | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/models/noise_floor_session.dart b/lib/models/noise_floor_session.dart index 47f2627..9c6b574 100644 --- a/lib/models/noise_floor_session.dart +++ b/lib/models/noise_floor_session.dart @@ -40,7 +40,7 @@ enum PingEventType { traceSuccess, // Cyan: Trace got response @HiveField(6) - traceFail, // Red: Trace no response + traceFail, // Grey: Trace no response } /// Repeater info for graph markers diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 213f662..55244f9 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -1127,21 +1127,21 @@ class _MapWidgetState extends State with TickerProviderStateMixin { Divider(height: 1, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3)), _buildLegendItem( context: context, - color: Colors.grey, - label: 'DISC', - description: 'Location where you sent a discovery request but no repeater responded', + color: Colors.cyan, + label: 'TRC', + description: 'Location where a trace reached the repeater', ), Divider(height: 1, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2)), _buildLegendItem( context: context, - color: Colors.cyan, - label: 'TRC', - description: 'Location where a trace reached the repeater', + color: Colors.grey, + label: 'DISC', + description: 'Location where you sent a discovery request but no repeater responded', ), Divider(height: 1, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2)), _buildLegendItem( context: context, - color: Colors.red, + color: Colors.grey, label: 'TRC', description: 'Location where a trace got no response', ), @@ -1628,7 +1628,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { onTap: () => _showTraceDetails(entry), child: Container( decoration: BoxDecoration( - color: entry.success ? Colors.cyan : Colors.red, + color: entry.success ? Colors.cyan : Colors.grey, shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), boxShadow: const [ diff --git a/lib/widgets/noise_floor_chart.dart b/lib/widgets/noise_floor_chart.dart index d88357d..aa760b4 100644 --- a/lib/widgets/noise_floor_chart.dart +++ b/lib/widgets/noise_floor_chart.dart @@ -849,11 +849,11 @@ class InteractiveNoiseFloorChartState extends State alignment: WrapAlignment.center, children: [ _legendItem(context, Colors.green, 'TX Success'), - _legendItem(context, Colors.red, 'TX/Trace Fail'), + _legendItem(context, Colors.red, 'TX Fail'), _legendItem(context, Colors.blue, 'RX'), _legendItem(context, Colors.purple, 'DISC Success'), - _legendItem(context, Colors.grey, 'DISC Fail'), _legendItem(context, Colors.cyan, 'Trace Success'), + _legendItem(context, Colors.grey, 'No Response'), ], ); } From 8f71d52ce97fd1fb3d035fe48fecd9f8b0558f60 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Mon, 16 Mar 2026 21:30:43 -0400 Subject: [PATCH 48/57] Log tab redesign --- lib/models/log_entry.dart | 41 + lib/providers/app_state_provider.dart | 10 + lib/screens/connection_screen.dart | 3 +- lib/screens/graph_screen.dart | 5 +- lib/screens/log_screen.dart | 1540 ++++++++----------------- lib/screens/settings_screen.dart | 3 +- 6 files changed, 545 insertions(+), 1057 deletions(-) diff --git a/lib/models/log_entry.dart b/lib/models/log_entry.dart index f0a468d..26429be 100644 --- a/lib/models/log_entry.dart +++ b/lib/models/log_entry.dart @@ -181,6 +181,47 @@ enum SnrSeverity { good, // Green: SNR > 5 dB } +/// Ping type for unified log view +enum PingLogType { tx, rx, disc, trace } + +/// Wrapper for unified chronological ping log view +class UnifiedPingLogEntry implements Comparable { + final PingLogType type; + final DateTime timestamp; + final dynamic entry; + + UnifiedPingLogEntry({required this.type, required this.timestamp, required this.entry}); + + TxLogEntry get asTx => entry as TxLogEntry; + RxLogEntry get asRx => entry as RxLogEntry; + DiscLogEntry get asDisc => entry as DiscLogEntry; + TraceLogEntry get asTrace => entry as TraceLogEntry; + + @override + int compareTo(UnifiedPingLogEntry other) => other.timestamp.compareTo(timestamp); + + String get timeString => switch (type) { + PingLogType.tx => asTx.timeString, + PingLogType.rx => asRx.timeString, + PingLogType.disc => asDisc.timeString, + PingLogType.trace => asTrace.timeString, + }; + + String get locationString => switch (type) { + PingLogType.tx => asTx.locationString, + PingLogType.rx => asRx.locationString, + PingLogType.disc => asDisc.locationString, + PingLogType.trace => asTrace.locationString, + }; + + String toCsv() => switch (type) { + PingLogType.tx => 'TX,${asTx.toCsv()}', + PingLogType.rx => 'RX,${asRx.toCsv()}', + PingLogType.disc => 'DISC,${asDisc.toCsv()}', + PingLogType.trace => 'TRC,${asTrace.toCsv()}', + }; +} + /// User Error Entry for error log class UserErrorEntry { final DateTime timestamp; diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 98b5170..b152b1b 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -342,6 +342,16 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { List get discLogEntries => List.unmodifiable(_discLogEntries); List get traceLogEntries => List.unmodifiable(_traceLogEntries); List get errorLogEntries => List.unmodifiable(_errorLogEntries); + List get unifiedPingLogEntries { + final merged = [ + ..._txLogEntries.map((e) => UnifiedPingLogEntry(type: PingLogType.tx, timestamp: e.timestamp, entry: e)), + ..._rxLogEntries.map((e) => UnifiedPingLogEntry(type: PingLogType.rx, timestamp: e.timestamp, entry: e)), + ..._discLogEntries.map((e) => UnifiedPingLogEntry(type: PingLogType.disc, timestamp: e.timestamp, entry: e)), + ..._traceLogEntries.map((e) => UnifiedPingLogEntry(type: PingLogType.trace, timestamp: e.timestamp, entry: e)), + ]; + merged.sort(); + return merged; + } ({double lat, double lon})? get mapNavigationTarget => _mapNavigationTarget; int get mapNavigationTrigger => _mapNavigationTrigger; bool get requestMapTabSwitch => _requestMapTabSwitch; diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index edc35d4..d8134f9 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -78,7 +78,8 @@ class _ConnectionScreenState extends State with WidgetsBinding return Scaffold( appBar: AppBar( - title: const Text('Connection'), + toolbarHeight: 40, + title: const Text('Connection', style: TextStyle(fontSize: 18)), automaticallyImplyLeading: false, ), body: _buildBody(context, appState), diff --git a/lib/screens/graph_screen.dart b/lib/screens/graph_screen.dart index b9a4141..977ce8c 100644 --- a/lib/screens/graph_screen.dart +++ b/lib/screens/graph_screen.dart @@ -19,12 +19,13 @@ class GraphScreen extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text('Noise Floor History'), + toolbarHeight: 40, + title: const Text('Noise Floor History', style: TextStyle(fontSize: 18)), automaticallyImplyLeading: false, actions: [ if (sessions.isNotEmpty) IconButton( - icon: const Icon(Icons.delete_outline), + icon: const Icon(Icons.delete_outline, size: 20), onPressed: () => _confirmClearSessions(context, appState), tooltip: 'Clear all sessions', ), diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index e172340..02e6bb8 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -6,7 +6,7 @@ import '../models/log_entry.dart'; import '../providers/app_state_provider.dart'; import '../widgets/repeater_id_chip.dart'; -/// Log screen with tabs for TX Log, RX Log, and User Errors +/// Log screen with two tabs: All Pings (unified TX+RX+DISC+TRC) and Errors class LogScreen extends StatefulWidget { const LogScreen({super.key}); @@ -20,7 +20,7 @@ class _LogScreenState extends State with SingleTickerProviderStateMix @override void initState() { super.initState(); - _tabController = TabController(length: 5, vsync: this); + _tabController = TabController(length: 2, vsync: this); } @override @@ -36,259 +36,130 @@ class _LogScreenState extends State with SingleTickerProviderStateMix // Auto-switch to Error tab when requested if (appState.requestErrorLogSwitch) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted && _tabController.index != 4) { - _tabController.animateTo(4); // Switch to Error tab + if (mounted && _tabController.index != 1) { + _tabController.animateTo(1); // Switch to Error tab setState(() {}); } appState.clearErrorLogSwitchRequest(); }); } + final totalPings = appState.txLogEntries.length + + appState.rxLogEntries.length + + appState.discLogEntries.length + + appState.traceLogEntries.length; + + final errorCount = appState.errorLogEntries.length; + return Scaffold( appBar: AppBar( - title: const Text('Logs'), + toolbarHeight: 40, + title: const Text('Logs', style: TextStyle(fontSize: 18)), actions: [ - IconButton( - icon: const Icon(Icons.copy), - onPressed: () => _copyCurrentTabToCsv(context, appState), - tooltip: 'Copy CSV', - ), - IconButton( - icon: const Icon(Icons.delete_outline), - onPressed: () => _confirmClearLogs(context, appState), - tooltip: 'Clear all logs', + PopupMenuButton( + icon: const Icon(Icons.more_vert, size: 20), + padding: EdgeInsets.zero, + onSelected: (value) { + if (value == 'copy') _copyCurrentTabToCsv(context, appState); + if (value == 'clear') _confirmClearLogs(context, appState); + }, + itemBuilder: (context) => [ + const PopupMenuItem(value: 'copy', child: Text('Copy CSV')), + const PopupMenuItem(value: 'clear', child: Text('Clear all logs')), + ], ), ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(32), + child: TabBar( + controller: _tabController, + indicatorSize: TabBarIndicatorSize.tab, + dividerHeight: 1, + labelPadding: EdgeInsets.zero, + tabs: [ + Tab(height: 32, text: 'All Pings${totalPings > 0 ? ' ($totalPings)' : ''}'), + Tab(height: 32, text: 'Errors${errorCount > 0 ? ' ($errorCount)' : ''}'), + ], + ), + ), ), - body: Column( + body: TabBarView( + controller: _tabController, children: [ - // Secondary bar with tabs (full width) - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.15), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - children: [ - Expanded(child: _buildTabChip(0, 'TX', appState.txLogEntries.length, isTx: true)), - const SizedBox(width: 6), - Expanded(child: _buildTabChip(1, 'RX', appState.rxLogEntries.length, isRx: true)), - const SizedBox(width: 6), - Expanded(child: _buildTabChip(2, 'DISC', appState.discLogEntries.length, isDisc: true)), - const SizedBox(width: 6), - Expanded(child: _buildTabChip(3, 'TRC', appState.traceLogEntries.length, isTrace: true)), - const SizedBox(width: 6), - Expanded(child: _buildTabChip(4, 'Err', appState.errorLogEntries.length, isError: true)), - ], - ), - ), - // Tab content - Expanded( - child: TabBarView( - controller: _tabController, - children: [ - _TxLogTab(entries: appState.txLogEntries), - _RxLogTab(entries: appState.rxLogEntries), - _DiscLogTab(entries: appState.discLogEntries), - _TraceLogTab(entries: appState.traceLogEntries), - _ErrorLogTab(entries: appState.errorLogEntries), - ], - ), + _AllPingsTab( + allEntries: appState.unifiedPingLogEntries, + txCount: appState.txLogEntries.length, + rxCount: appState.rxLogEntries.length, + discCount: appState.discLogEntries.length, + traceCount: appState.traceLogEntries.length, ), + _ErrorLogTab(entries: appState.errorLogEntries), ], ), ); } - /// Build a tab chip that matches StatusBar chip styling - Widget _buildTabChip(int index, String label, int count, {bool isError = false, bool isDisc = false, bool isTx = false, bool isRx = false, bool isTrace = false}) { - final theme = Theme.of(context); - // Colors matching status bar chips - const discColor = Color(0xFF7B68EE); // DISC purple - const txColor = Colors.green; // TX green (matches status bar) - const rxColor = Colors.blue; // RX blue (matches status bar) - const traceColor = Colors.cyan; // TRC cyan (matches noise floor chart) - - return GestureDetector( - onTap: () { - _tabController.animateTo(index); - setState(() {}); - }, - child: AnimatedBuilder( - animation: _tabController, - builder: (context, child) { - final isCurrentlySelected = _tabController.index == index; - Color currentColor; - if (isCurrentlySelected) { - if (isError) { - currentColor = Colors.red; - } else if (isDisc) { - currentColor = discColor; - } else if (isTrace) { - currentColor = traceColor; - } else if (isTx) { - currentColor = txColor; - } else if (isRx) { - currentColor = rxColor; - } else { - currentColor = theme.colorScheme.primary; - } - } else { - currentColor = theme.colorScheme.onSurfaceVariant; - } - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: currentColor.withValues(alpha: isCurrentlySelected ? 0.15 : 0.08), - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: currentColor.withValues(alpha: isCurrentlySelected ? 0.4 : 0.2), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: Text( - label, - overflow: TextOverflow.clip, - softWrap: false, - style: TextStyle( - fontSize: 12, - fontWeight: isCurrentlySelected ? FontWeight.w600 : FontWeight.w500, - color: currentColor, - ), - ), - ), - if (count > 0) ...[ - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), - decoration: BoxDecoration( - color: currentColor, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - count > 99 ? '99+' : count.toString(), - style: const TextStyle( - fontSize: 9, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ], - ], - ), - ); - }, - ), - ); - } - void _copyCurrentTabToCsv(BuildContext context, AppStateProvider appState) { - final currentTab = _tabController.index; - - switch (currentTab) { - case 0: // TX Log - _copyTxLogToCsv(context, appState.txLogEntries); - break; - case 1: // RX Log - _copyRxLogToCsv(context, appState.rxLogEntries); - break; - case 2: // DISC Log - _copyDiscLogToCsv(context, appState.discLogEntries); - break; - case 3: // TRC Log - _copyTraceLogToCsv(context, appState.traceLogEntries); - break; - case 4: // Error Log - _copyErrorLogToCsv(context, appState.errorLogEntries); - break; + if (_tabController.index == 0) { + _copyAllPingsToCsv(context, appState); + } else { + _copyErrorLogToCsv(context, appState.errorLogEntries); } } - void _copyTxLogToCsv(BuildContext context, List entries) { - if (entries.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No TX log entries to copy'), duration: Duration(seconds: 2)), - ); - return; - } + void _copyAllPingsToCsv(BuildContext context, AppStateProvider appState) { + final tx = appState.txLogEntries; + final rx = appState.rxLogEntries; + final disc = appState.discLogEntries; + final trace = appState.traceLogEntries; - final buffer = StringBuffer(); - buffer.writeln('timestamp,latitude,longitude,power,events'); - for (final entry in entries) { - buffer.writeln(entry.toCsv()); - } - Clipboard.setData(ClipboardData(text: buffer.toString())); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('TX log copied to clipboard'), duration: Duration(seconds: 2)), - ); - } - - void _copyRxLogToCsv(BuildContext context, List entries) { - if (entries.isEmpty) { + if (tx.isEmpty && rx.isEmpty && disc.isEmpty && trace.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No RX log entries to copy'), duration: Duration(seconds: 2)), + const SnackBar(content: Text('No ping log entries to copy'), duration: Duration(seconds: 2)), ); return; } final buffer = StringBuffer(); - buffer.writeln('timestamp,repeater_id,snr,rssi,path_length,header,latitude,longitude'); - for (final entry in entries) { - buffer.writeln(entry.toCsv()); - } - Clipboard.setData(ClipboardData(text: buffer.toString())); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('RX log copied to clipboard'), duration: Duration(seconds: 2)), - ); - } - void _copyDiscLogToCsv(BuildContext context, List entries) { - if (entries.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No DISC log entries to copy'), duration: Duration(seconds: 2)), - ); - return; + if (tx.isNotEmpty) { + buffer.writeln('--- TX Log ---'); + buffer.writeln('timestamp,latitude,longitude,power,events'); + for (final entry in tx) { + buffer.writeln(entry.toCsv()); + } + buffer.writeln(); } - final buffer = StringBuffer(); - buffer.writeln('timestamp,latitude,longitude,noisefloor,node_count,nodes'); - for (final entry in entries) { - buffer.writeln(entry.toCsv()); + if (rx.isNotEmpty) { + buffer.writeln('--- RX Log ---'); + buffer.writeln('timestamp,repeater_id,snr,rssi,path_length,header,latitude,longitude'); + for (final entry in rx) { + buffer.writeln(entry.toCsv()); + } + buffer.writeln(); } - Clipboard.setData(ClipboardData(text: buffer.toString())); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('DISC log copied to clipboard'), duration: Duration(seconds: 2)), - ); - } - void _copyTraceLogToCsv(BuildContext context, List entries) { - if (entries.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No trace log entries to copy'), duration: Duration(seconds: 2)), - ); - return; + if (disc.isNotEmpty) { + buffer.writeln('--- DISC Log ---'); + buffer.writeln('timestamp,latitude,longitude,noisefloor,node_count,nodes'); + for (final entry in disc) { + buffer.writeln(entry.toCsv()); + } + buffer.writeln(); } - final buffer = StringBuffer(); - buffer.writeln('timestamp,target_repeater,local_snr,local_rssi,remote_snr,latitude,longitude,noisefloor,success'); - for (final entry in entries) { - buffer.writeln(entry.toCsv()); + if (trace.isNotEmpty) { + buffer.writeln('--- TRC Log ---'); + buffer.writeln('timestamp,target_repeater,local_snr,local_rssi,remote_snr,latitude,longitude,noisefloor,success'); + for (final entry in trace) { + buffer.writeln(entry.toCsv()); + } } + Clipboard.setData(ClipboardData(text: buffer.toString())); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Trace log copied to clipboard'), duration: Duration(seconds: 2)), + const SnackBar(content: Text('All ping logs copied to clipboard'), duration: Duration(seconds: 2)), ); } @@ -335,457 +206,199 @@ class _LogScreenState extends State with SingleTickerProviderStateMix } } -/// TX Log Tab -class _TxLogTab extends StatelessWidget { - final List entries; +// ============================================================================= +// All Pings Tab — unified chronological view with type filters +// ============================================================================= + +class _AllPingsTab extends StatefulWidget { + final List allEntries; + final int txCount; + final int rxCount; + final int discCount; + final int traceCount; + + const _AllPingsTab({ + required this.allEntries, + required this.txCount, + required this.rxCount, + required this.discCount, + required this.traceCount, + }); - const _TxLogTab({required this.entries}); + @override + State<_AllPingsTab> createState() => _AllPingsTabState(); +} + +class _AllPingsTabState extends State<_AllPingsTab> { + final Set _activeFilters = { + PingLogType.tx, + PingLogType.rx, + PingLogType.disc, + PingLogType.trace, + }; + + void _toggleFilter(PingLogType type) { + setState(() { + if (_activeFilters.contains(type)) { + // Don't allow deselecting the last filter + if (_activeFilters.length > 1) { + _activeFilters.remove(type); + } + } else { + _activeFilters.add(type); + } + }); + } @override Widget build(BuildContext context) { - if (entries.isEmpty) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.upload_outlined, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(height: 16), - Text('No TX pings logged yet', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), - ], + final filtered = widget.allEntries + .where((e) => _activeFilters.contains(e.type)) + .toList(); + + return Column( + children: [ + // Filter segmented row + Padding( + padding: const EdgeInsets.fromLTRB(12, 4, 12, 0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3)), + ), + clipBehavior: Clip.antiAlias, + child: IntrinsicHeight( + child: Row( + children: [ + _buildFilterSegment(PingLogType.tx, 'TX', widget.txCount, Colors.green, isFirst: true), + _segmentDivider(context), + _buildFilterSegment(PingLogType.rx, 'RX', widget.rxCount, Colors.blue), + _segmentDivider(context), + _buildFilterSegment(PingLogType.disc, 'DISC', widget.discCount, const Color(0xFF7B68EE)), + _segmentDivider(context), + _buildFilterSegment(PingLogType.trace, 'TRC', widget.traceCount, Colors.cyan, isLast: true), + ], + ), + ), + ), ), - ); - } - - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: entries.length, - itemBuilder: (context, index) { - // Most recent first (no reverse needed - entries already in chronological order) - final entry = entries[entries.length - 1 - index]; - return _buildTxEntry(context, entry); - }, + // List + Expanded( + child: filtered.isEmpty + ? Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.list_alt, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant), + const SizedBox(height: 16), + Text('No pings logged yet', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), + ], + ), + ) + : ListView.builder( + padding: const EdgeInsets.fromLTRB(12, 8, 12, 12), + itemCount: filtered.length, + itemBuilder: (context, index) { + final unified = filtered[index]; + return switch (unified.type) { + PingLogType.tx => _buildTxCard(context, unified.asTx), + PingLogType.rx => _buildRxCard(context, unified.asRx), + PingLogType.disc => _buildDiscCard(context, unified.asDisc), + PingLogType.trace => _buildTraceCard(context, unified.asTrace), + }; + }, + ), + ), + ], ); } - Widget _buildTxEntry(BuildContext context, TxLogEntry entry) { - final appState = context.read(); - - return Card( - margin: const EdgeInsets.only(bottom: 8), - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: InkWell( - onTap: () { - // Navigate to map and show this location - // Main scaffold will handle switching to map tab - appState.navigateToMapCoordinates(entry.latitude, entry.longitude); - }, - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header row: Time and Power - Row( - children: [ - // Time badge + Widget _buildFilterSegment(PingLogType type, String label, int count, Color color, {bool isFirst = false, bool isLast = false}) { + final active = _activeFilters.contains(type); + return Expanded( + child: GestureDetector( + onTap: () => _toggleFilter(type), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 7), + color: active ? color.withValues(alpha: 0.12) : Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + label, + style: TextStyle( + fontSize: 12, + fontWeight: active ? FontWeight.w600 : FontWeight.w500, + color: active ? color : Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.6), + ), + ), + if (count > 0) ...[ + const SizedBox(width: 4), Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(6), + color: active ? color : Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(8), ), child: Text( - entry.timeString, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: Theme.of(context).colorScheme.onSurface, + count > 99 ? '99+' : count.toString(), + style: const TextStyle( + fontSize: 9, + fontWeight: FontWeight.bold, + color: Colors.white, ), ), ), - const Spacer(), - // Power indicator (watts) - Text( - '${entry.power.toStringAsFixed(1)} W', - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), - ], - ), - const SizedBox(height: 8), - - // Location - Row( - children: [ - Icon(Icons.location_on, size: 14, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(width: 4), - Text( - entry.locationString, - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), ], - ), - - // Repeaters table - if (entry.events.isNotEmpty) ...[ - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), - ), - child: Column( - children: [ - // Header row - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), - child: Row( - children: [ - SizedBox( - width: 60, - child: Text( - 'Node', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - ], - ), - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - // Data rows - ...entry.events.map((event) => _buildRepeaterRow(context, event)), - ], - ), - ), - ] else ...[ - const SizedBox(height: 8), - Text( - 'No repeaters heard', - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontStyle: FontStyle.italic, - ), - ), ], - ], + ), ), ), - ), ); } - /// Build a table row for a repeater event - Widget _buildRepeaterRow(BuildContext context, RxEvent event) { - Color snrColor; - switch (event.severity) { - case SnrSeverity.poor: - snrColor = Colors.red; - case SnrSeverity.fair: - snrColor = Colors.orange; - case SnrSeverity.good: - snrColor = Colors.green; - case null: - snrColor = Colors.grey; - } - - // RSSI color based on signal strength - Color rssiColor; - if (event.rssi == null) { - rssiColor = Colors.grey; - } else if (event.rssi! >= -70) { - rssiColor = Colors.green; - } else if (event.rssi! >= -100) { - rssiColor = Colors.orange; - } else { - rssiColor = Colors.red; - } - - return InkWell( - onTap: () => RepeaterIdChip.showRepeaterPopup(context, event.repeaterId), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), - child: Row( - children: [ - // Repeater ID - RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 11, width: 60), - // SNR - Expanded( - child: Center( - child: _buildTxChip(event.snr?.toStringAsFixed(1) ?? '-', snrColor), - ), - ), - // RSSI - Expanded( - child: Center( - child: _buildTxChip(event.rssi != null ? '${event.rssi}' : '-', rssiColor), - ), - ), - ], - ), - ), + static Widget _segmentDivider(BuildContext context) { + return VerticalDivider( + width: 1, + thickness: 1, + color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2), ); } - /// Build a small colored chip for TX table cells - Widget _buildTxChip(String value, Color color) { + // --------------------------------------------------------------------------- + // Type badge + // --------------------------------------------------------------------------- + + static Widget _buildTypeBadge(PingLogType type) { + final (label, color) = switch (type) { + PingLogType.tx => ('TX', Colors.green), + PingLogType.rx => ('RX', Colors.blue), + PingLogType.disc => ('DISC', const Color(0xFF7B68EE)), + PingLogType.trace => ('TRC', Colors.cyan), + }; return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: color.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(4), - border: Border.all(color: color.withValues(alpha: 0.4)), - ), - child: Text( - value, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: color, - fontFamily: 'monospace', - ), - ), - ); - } -} - -/// RX Log Tab -class _RxLogTab extends StatelessWidget { - final List entries; - - const _RxLogTab({required this.entries}); - - @override - Widget build(BuildContext context) { - if (entries.isEmpty) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.download_outlined, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(height: 16), - Text('No RX observations yet', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), - ], - ), - ); - } - - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: entries.length, - itemBuilder: (context, index) { - // Most recent first (no reverse needed - entries already in chronological order) - final entry = entries[entries.length - 1 - index]; - return _buildRxEntry(context, entry); - }, - ); - } - - Widget _buildRxEntry(BuildContext context, RxLogEntry entry) { - final appState = context.read(); - - Color snrColor; - switch (entry.severity) { - case SnrSeverity.poor: - snrColor = Colors.red; - case SnrSeverity.fair: - snrColor = Colors.orange; - case SnrSeverity.good: - snrColor = Colors.green; - case null: - snrColor = Colors.grey; - } - - // RSSI color based on signal strength - Color rssiColor; - if (entry.rssi == null) { - rssiColor = Colors.grey; - } else if (entry.rssi! >= -70) { - rssiColor = Colors.green; // Strong: -30 to -70 dBm - } else if (entry.rssi! >= -100) { - rssiColor = Colors.orange; // Medium: -70 to -100 dBm - } else { - rssiColor = Colors.red; // Weak: -100 to -120 dBm - } - - return Card( - margin: const EdgeInsets.only(bottom: 8), - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: InkWell( - onTap: () { - // Navigate to map and show this location - // Main scaffold will handle switching to map tab - appState.navigateToMapCoordinates(entry.latitude, entry.longitude); - }, - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header row: Time badge only - Row( - children: [ - // Time badge - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - entry.timeString, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: Theme.of(context).colorScheme.onSurface, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - - // Location - Row( - children: [ - Icon(Icons.location_on, size: 14, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(width: 4), - Text( - entry.locationString, - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), - ], - ), - const SizedBox(height: 10), - - // Repeater table (single row) - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), - ), - child: Column( - children: [ - // Header row - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), - child: Row( - children: [ - SizedBox( - width: 60, - child: Text( - 'Node', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - ], - ), - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - // Data row - InkWell( - onTap: () => RepeaterIdChip.showRepeaterPopup(context, entry.repeaterId), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), - child: Row( - children: [ - // Repeater ID - RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 11, width: 60), - // SNR - Expanded( - child: Center( - child: _buildRxChip(entry.snr?.toStringAsFixed(1) ?? '-', snrColor), - ), - ), - // RSSI - Expanded( - child: Center( - child: _buildRxChip(entry.rssi != null ? '${entry.rssi}' : '-', rssiColor), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ], - ), + borderRadius: BorderRadius.circular(4), + border: Border.all(color: color.withValues(alpha: 0.4)), ), + child: Text( + label, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: color, ), + ), ); } - /// Build a small colored chip for RX table cells - Widget _buildRxChip(String value, Color color) { + // --------------------------------------------------------------------------- + // Shared chip builder + // --------------------------------------------------------------------------- + + static Widget _buildChip(String value, Color color) { return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( @@ -804,108 +417,172 @@ class _RxLogTab extends StatelessWidget { ), ); } -} -/// DISC Log Tab (Discovery observations from Passive Mode) -class _DiscLogTab extends StatelessWidget { - final List entries; + // --------------------------------------------------------------------------- + // TX Card + // --------------------------------------------------------------------------- + + Widget _buildTxCard(BuildContext context, TxLogEntry entry) { + final appState = context.read(); + return Card( + margin: const EdgeInsets.only(bottom: 8), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + child: InkWell( + onTap: () => appState.navigateToMapCoordinates(entry.latitude, entry.longitude), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildCardHeader(context, PingLogType.tx, entry.timeString, entry.locationString), + // Repeaters table + if (entry.events.isNotEmpty) ...[ + const SizedBox(height: 10), + _buildRepeaterTable(context, entry.events), + ] else ...[ + const SizedBox(height: 8), + Text( + 'No repeaters heard', + style: TextStyle( + fontSize: 11, + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontStyle: FontStyle.italic, + ), + ), + ], + ], + ), + ), + ), + ); + } - const _DiscLogTab({required this.entries}); + Widget _buildRepeaterTable(BuildContext context, List events) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + child: Row( + children: [ + SizedBox(width: 60, child: _tableHeader(context, 'Node')), + Expanded(child: _tableHeader(context, 'SNR', center: true)), + Expanded(child: _tableHeader(context, 'RSSI', center: true)), + ], + ), + ), + Divider(height: 1, color: Theme.of(context).dividerColor), + ...events.map((event) => _buildTxRepeaterRow(context, event)), + ], + ), + ); + } - @override - Widget build(BuildContext context) { - if (entries.isEmpty) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, + Widget _buildTxRepeaterRow(BuildContext context, RxEvent event) { + final snrColor = _snrColor(event.severity); + final rssiColor = _rssiColor(event.rssi); + return InkWell( + onTap: () => RepeaterIdChip.showRepeaterPopup(context, event.repeaterId), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: Row( children: [ - Icon(Icons.radar_outlined, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(height: 16), - Text('No discovery observations yet', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), - const SizedBox(height: 8), - Text('Enable Passive Mode to discover nearby nodes', - style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 12)), + RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 11, width: 60), + Expanded(child: Center(child: _buildChip(event.snr?.toStringAsFixed(1) ?? '-', snrColor))), + Expanded(child: Center(child: _buildChip(event.rssi != null ? '${event.rssi}' : '-', rssiColor))), ], ), - ); - } - - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: entries.length, - itemBuilder: (context, index) { - final entry = entries[index]; // Already sorted most recent first - return _buildDiscEntry(context, entry); - }, + ), ); } - Widget _buildDiscEntry(BuildContext context, DiscLogEntry entry) { + // --------------------------------------------------------------------------- + // RX Card + // --------------------------------------------------------------------------- + + Widget _buildRxCard(BuildContext context, RxLogEntry entry) { final appState = context.read(); + final snrColor = _snrColor(entry.severity); + final rssiColor = _rssiColor(entry.rssi); return Card( margin: const EdgeInsets.only(bottom: 8), color: Theme.of(context).colorScheme.surfaceContainerHigh, child: InkWell( - onTap: () { - // Navigate to map and show this location - appState.navigateToMapCoordinates(entry.latitude, entry.longitude); - }, + onTap: () => appState.navigateToMapCoordinates(entry.latitude, entry.longitude), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Header row: Time and node count (matching TX log style) - Row( - children: [ - // Time badge - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - entry.timeString, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: Theme.of(context).colorScheme.onSurface, + _buildCardHeader(context, PingLogType.rx, entry.timeString, entry.locationString), + const SizedBox(height: 10), + // Repeater table (single row) + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.5)), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + child: Row( + children: [ + SizedBox(width: 60, child: _tableHeader(context, 'Node')), + Expanded(child: _tableHeader(context, 'SNR', center: true)), + Expanded(child: _tableHeader(context, 'RSSI', center: true)), + ], ), ), - ), - const Spacer(), - // Node count indicator (like power indicator in TX log) - Text( - '${entry.nodeCount} node${entry.nodeCount == 1 ? '' : 's'}', - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontFamily: 'monospace', + Divider(height: 1, color: Theme.of(context).dividerColor), + InkWell( + onTap: () => RepeaterIdChip.showRepeaterPopup(context, entry.repeaterId), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: Row( + children: [ + RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 11, width: 60), + Expanded(child: Center(child: _buildChip(entry.snr?.toStringAsFixed(1) ?? '-', snrColor))), + Expanded(child: Center(child: _buildChip(entry.rssi != null ? '${entry.rssi}' : '-', rssiColor))), + ], + ), + ), ), - ), - ], + ], + ), ), - const SizedBox(height: 8), + ], + ), + ), + ), + ); + } - // Location - Row( - children: [ - Icon(Icons.location_on, size: 14, color: Theme.of(context).colorScheme.onSurfaceVariant), - const SizedBox(width: 4), - Text( - entry.locationString, - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), - ], - ), + // --------------------------------------------------------------------------- + // DISC Card + // --------------------------------------------------------------------------- + + Widget _buildDiscCard(BuildContext context, DiscLogEntry entry) { + final appState = context.read(); + return Card( + margin: const EdgeInsets.only(bottom: 8), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + child: InkWell( + onTap: () => appState.navigateToMapCoordinates(entry.latitude, entry.longitude), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildCardHeader(context, PingLogType.disc, entry.timeString, entry.locationString), // Nodes table if (entry.discoveredNodes.isNotEmpty) ...[ const SizedBox(height: 10), @@ -917,61 +594,19 @@ class _DiscLogTab extends StatelessWidget { ), child: Column( children: [ - // Header row Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), child: Row( children: [ - SizedBox( - width: 70, - child: Text( - 'Node', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'TX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ), + SizedBox(width: 70, child: _tableHeader(context, 'Node')), + Expanded(child: _tableHeader(context, 'RX SNR', center: true)), + Expanded(child: _tableHeader(context, 'RX RSSI', center: true)), + Expanded(child: _tableHeader(context, 'TX SNR', center: true)), ], ), ), Divider(height: 1, color: Theme.of(context).dividerColor), - // Data rows - ...entry.discoveredNodes.map((node) => _buildNodeRow(context, node)), + ...entry.discoveredNodes.map((node) => _buildDiscNodeRow(context, node)), ], ), ), @@ -993,20 +628,9 @@ class _DiscLogTab extends StatelessWidget { ); } - /// Build a table row for a discovered node - Widget _buildNodeRow(BuildContext context, DiscoveredNodeEntry node) { - // Color for RX SNR (what we received) - Color rxSnrColor; - switch (node.severity) { - case SnrSeverity.poor: - rxSnrColor = Colors.red; - case SnrSeverity.fair: - rxSnrColor = Colors.orange; - case SnrSeverity.good: - rxSnrColor = Colors.green; - } - - // TX SNR color (what they received from us) + Widget _buildDiscNodeRow(BuildContext context, DiscoveredNodeEntry node) { + final rxSnrColor = _snrColorFromValue(node.localSnr); + final rssiColor = _rssiColor(node.localRssi); Color txSnrColor; if (node.remoteSnr <= -1) { txSnrColor = Colors.red; @@ -1016,30 +640,17 @@ class _DiscLogTab extends StatelessWidget { txSnrColor = Colors.green; } - // RSSI color based on signal strength - Color rssiColor; - if (node.localRssi >= -70) { - rssiColor = Colors.green; - } else if (node.localRssi >= -100) { - rssiColor = Colors.orange; - } else { - rssiColor = Colors.red; - } - return InkWell( onTap: () => RepeaterIdChip.showRepeaterPopup(context, node.repeaterId, fullHexId: node.pubkeyHex), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), child: Row( children: [ - // Node ID with type SizedBox( width: 70, child: Row( children: [ - Flexible( - child: RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 11), - ), + Flexible(child: RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 11)), Text( node.nodeTypeLabel, style: const TextStyle( @@ -1051,97 +662,20 @@ class _DiscLogTab extends StatelessWidget { ], ), ), - // RX SNR - Expanded( - child: Center( - child: _buildChip(node.localSnr.toStringAsFixed(1), rxSnrColor), - ), - ), - // RSSI - Expanded( - child: Center( - child: _buildChip('${node.localRssi}', rssiColor), - ), - ), - // TX SNR - Expanded( - child: Center( - child: _buildChip(node.remoteSnr.toStringAsFixed(1), txSnrColor), - ), - ), + Expanded(child: Center(child: _buildChip(node.localSnr.toStringAsFixed(1), rxSnrColor))), + Expanded(child: Center(child: _buildChip('${node.localRssi}', rssiColor))), + Expanded(child: Center(child: _buildChip(node.remoteSnr.toStringAsFixed(1), txSnrColor))), ], ), ), ); } - /// Build a small colored chip for table cells - Widget _buildChip(String value, Color color) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: color.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(4), - border: Border.all(color: color.withValues(alpha: 0.4)), - ), - child: Text( - value, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: color, - fontFamily: 'monospace', - ), - ), - ); - } -} - -/// Trace Log Tab (Trace Mode results) -class _TraceLogTab extends StatelessWidget { - final List entries; - - const _TraceLogTab({required this.entries}); - - @override - Widget build(BuildContext context) { - if (entries.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.gps_fixed, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.3)), - const SizedBox(height: 16), - Text( - 'No trace results yet', - style: TextStyle( - fontSize: 16, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(height: 8), - Text( - 'Enter a repeater ID and start Trace Mode', - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.7), - ), - ), - ], - ), - ); - } - - return ListView.builder( - padding: const EdgeInsets.all(12), - itemCount: entries.length, - itemBuilder: (context, index) { - return _buildTraceEntry(context, entries[index]); - }, - ); - } + // --------------------------------------------------------------------------- + // Trace Card + // --------------------------------------------------------------------------- - Widget _buildTraceEntry(BuildContext context, TraceLogEntry entry) { + Widget _buildTraceCard(BuildContext context, TraceLogEntry entry) { final colorScheme = Theme.of(context).colorScheme; final appState = context.read(); @@ -1149,75 +683,14 @@ class _TraceLogTab extends StatelessWidget { margin: const EdgeInsets.only(bottom: 8), color: colorScheme.surfaceContainerHigh, child: InkWell( - onTap: () { - appState.navigateToMapCoordinates(entry.latitude, entry.longitude); - }, + onTap: () => appState.navigateToMapCoordinates(entry.latitude, entry.longitude), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Header row: Time and repeater ID (matching disc style) - Row( - children: [ - // Time badge (neutral, matching disc) - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - entry.timeString, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: colorScheme.onSurface, - ), - ), - ), - const Spacer(), - // Repeater ID + success/fail text - Text( - entry.targetRepeaterId, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 6), - Text( - entry.success ? 'responded' : 'no response', - style: TextStyle( - fontSize: 11, - color: colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), - ], - ), - const SizedBox(height: 8), - - // Location - Row( - children: [ - Icon(Icons.location_on, size: 14, color: colorScheme.onSurfaceVariant), - const SizedBox(width: 4), - Text( - entry.locationString, - style: TextStyle( - fontSize: 11, - color: colorScheme.onSurfaceVariant, - fontFamily: 'monospace', - ), - ), - ], - ), - - // Results table (matching disc style) + _buildCardHeader(context, PingLogType.trace, entry.timeString, entry.locationString), + // Results table if (entry.success) ...[ const SizedBox(height: 10), Container( @@ -1228,60 +701,18 @@ class _TraceLogTab extends StatelessWidget { ), child: Column( children: [ - // Header row Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), child: Row( children: [ - SizedBox( - width: 70, - child: Text( - 'Node', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'RX RSSI', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: colorScheme.onSurfaceVariant, - ), - ), - ), - Expanded( - child: Text( - 'TX SNR', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: colorScheme.onSurfaceVariant, - ), - ), - ), + SizedBox(width: 70, child: _tableHeader(context, 'Node')), + Expanded(child: _tableHeader(context, 'RX SNR', center: true)), + Expanded(child: _tableHeader(context, 'RX RSSI', center: true)), + Expanded(child: _tableHeader(context, 'TX SNR', center: true)), ], ), ), Divider(height: 1, color: Theme.of(context).dividerColor), - // Data row _buildTraceNodeRow(context, entry), ], ), @@ -1304,98 +735,101 @@ class _TraceLogTab extends StatelessWidget { ); } - /// Build the data row for a trace result (matching disc node row style) Widget _buildTraceNodeRow(BuildContext context, TraceLogEntry entry) { - // RX SNR color - final rxSnr = entry.localSnr; - Color rxSnrColor; - if (rxSnr == null) { - rxSnrColor = Colors.grey; - } else if (rxSnr <= -1) { - rxSnrColor = Colors.red; - } else if (rxSnr <= 5) { - rxSnrColor = Colors.orange; - } else { - rxSnrColor = Colors.green; - } - - // RSSI color - final rssi = entry.localRssi; - Color rssiColor; - if (rssi == null) { - rssiColor = Colors.grey; - } else if (rssi >= -70) { - rssiColor = Colors.green; - } else if (rssi >= -100) { - rssiColor = Colors.orange; - } else { - rssiColor = Colors.red; - } - - // TX SNR color (remote) - final txSnr = entry.remoteSnr; - Color txSnrColor; - if (txSnr == null) { - txSnrColor = Colors.grey; - } else if (txSnr <= -1) { - txSnrColor = Colors.red; - } else if (txSnr <= 5) { - txSnrColor = Colors.orange; - } else { - txSnrColor = Colors.green; - } + final rxSnrColor = _snrColorFromNullableValue(entry.localSnr); + final rssiColor = _rssiColor(entry.localRssi); + final txSnrColor = _snrColorFromNullableValue(entry.remoteSnr); return Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), child: Row( children: [ - SizedBox( - width: 70, - child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 11), - ), - Expanded( - child: Center( - child: _buildChip(rxSnr?.toStringAsFixed(1) ?? '-', rxSnrColor), - ), - ), - Expanded( - child: Center( - child: _buildChip(rssi != null ? '$rssi' : '-', rssiColor), - ), - ), - Expanded( - child: Center( - child: _buildChip(txSnr?.toStringAsFixed(1) ?? '-', txSnrColor), - ), - ), + SizedBox(width: 70, child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 11)), + Expanded(child: Center(child: _buildChip(entry.localSnr?.toStringAsFixed(1) ?? '-', rxSnrColor))), + Expanded(child: Center(child: _buildChip(entry.localRssi != null ? '${entry.localRssi}' : '-', rssiColor))), + Expanded(child: Center(child: _buildChip(entry.remoteSnr?.toStringAsFixed(1) ?? '-', txSnrColor))), ], ), ); } - /// Build a small colored chip for table cells (matching disc style) - Widget _buildChip(String value, Color color) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: color.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(4), - border: Border.all(color: color.withValues(alpha: 0.4)), - ), - child: Text( - value, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: color, - fontFamily: 'monospace', + // --------------------------------------------------------------------------- + // Shared helpers + // --------------------------------------------------------------------------- + + static Widget _buildCardHeader(BuildContext context, PingLogType type, String timeString, String locationString) { + return Row( + children: [ + _buildTypeBadge(type), + const SizedBox(width: 6), + Text( + timeString, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: Theme.of(context).colorScheme.onSurface, + ), + ), + const Spacer(), + Icon(Icons.location_on, size: 14, color: Theme.of(context).colorScheme.onSurfaceVariant), + const SizedBox(width: 2), + Text( + locationString, + style: TextStyle( + fontSize: 11, + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontFamily: 'monospace', + ), ), + ], + ); + } + + static Widget _tableHeader(BuildContext context, String text, {bool center = false}) { + return Text( + text, + textAlign: center ? TextAlign.center : TextAlign.left, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ); } + + static Color _snrColor(SnrSeverity? severity) { + return switch (severity) { + SnrSeverity.poor => Colors.red, + SnrSeverity.fair => Colors.orange, + SnrSeverity.good => Colors.green, + null => Colors.grey, + }; + } + + static Color _snrColorFromValue(double snr) { + if (snr <= -1) return Colors.red; + if (snr <= 5) return Colors.orange; + return Colors.green; + } + + static Color _snrColorFromNullableValue(double? snr) { + if (snr == null) return Colors.grey; + return _snrColorFromValue(snr); + } + + static Color _rssiColor(int? rssi) { + if (rssi == null) return Colors.grey; + if (rssi >= -70) return Colors.green; + if (rssi >= -100) return Colors.orange; + return Colors.red; + } } -/// Error Log Tab +// ============================================================================= +// Error Log Tab (unchanged) +// ============================================================================= + class _ErrorLogTab extends StatelessWidget { final List entries; @@ -1420,7 +854,7 @@ class _ErrorLogTab extends StatelessWidget { padding: const EdgeInsets.all(16), itemCount: entries.length, itemBuilder: (context, index) { - // Most recent first (no reverse needed - entries already in chronological order) + // Most recent first final entry = entries[entries.length - 1 - index]; return _buildErrorEntry(context, entry); }, diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 873ad1d..e6332d5 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -102,7 +102,8 @@ class _SettingsScreenState extends State { return Scaffold( appBar: AppBar( - title: const Text('Settings'), + toolbarHeight: 40, + title: const Text('Settings', style: TextStyle(fontSize: 18)), automaticallyImplyLeading: false, ), body: ListView( From 6a670d68e4615cc8d0f34391df231b3101e1742a Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 06:43:37 -0400 Subject: [PATCH 49/57] Resigned log & settings screen --- lib/screens/log_screen.dart | 213 ++++- lib/screens/settings_screen.dart | 1468 +++++++++++++++--------------- 2 files changed, 924 insertions(+), 757 deletions(-) diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index 02e6bb8..53598dd 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../models/log_entry.dart'; +import '../models/repeater.dart'; import '../providers/app_state_provider.dart'; import '../widgets/repeater_id_chip.dart'; @@ -16,6 +17,7 @@ class LogScreen extends StatefulWidget { class _LogScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; + final _allPingsKey = GlobalKey<_AllPingsTabState>(); @override void initState() { @@ -87,7 +89,9 @@ class _LogScreenState extends State with SingleTickerProviderStateMix controller: _tabController, children: [ _AllPingsTab( + key: _allPingsKey, allEntries: appState.unifiedPingLogEntries, + repeaters: appState.repeaters, txCount: appState.txLogEntries.length, rxCount: appState.rxLogEntries.length, discCount: appState.discLogEntries.length, @@ -108,6 +112,29 @@ class _LogScreenState extends State with SingleTickerProviderStateMix } void _copyAllPingsToCsv(BuildContext context, AppStateProvider appState) { + // If a search filter is active, export only the filtered unified entries + final tabState = _allPingsKey.currentState; + final searchQuery = tabState?._searchQuery ?? ''; + if (searchQuery.isNotEmpty && tabState != null) { + final filtered = tabState._filteredEntries; + if (filtered.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('No matching entries to copy'), duration: Duration(seconds: 2)), + ); + return; + } + final buffer = StringBuffer(); + buffer.writeln('type,data'); + for (final entry in filtered) { + buffer.writeln(entry.toCsv()); + } + Clipboard.setData(ClipboardData(text: buffer.toString())); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('${filtered.length} filtered entries copied to clipboard'), duration: const Duration(seconds: 2)), + ); + return; + } + final tx = appState.txLogEntries; final rx = appState.rxLogEntries; final disc = appState.discLogEntries; @@ -212,13 +239,16 @@ class _LogScreenState extends State with SingleTickerProviderStateMix class _AllPingsTab extends StatefulWidget { final List allEntries; + final List repeaters; final int txCount; final int rxCount; final int discCount; final int traceCount; const _AllPingsTab({ + super.key, required this.allEntries, + required this.repeaters, required this.txCount, required this.rxCount, required this.discCount, @@ -237,6 +267,18 @@ class _AllPingsTabState extends State<_AllPingsTab> { PingLogType.trace, }; + String _searchQuery = ''; + final TextEditingController _searchController = TextEditingController(); + + /// Current filtered entries (used by CSV export) + List _filteredEntries = []; + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + void _toggleFilter(PingLogType type) { setState(() { if (_activeFilters.contains(type)) { @@ -250,14 +292,136 @@ class _AllPingsTabState extends State<_AllPingsTab> { }); } + // --------------------------------------------------------------------------- + // Repeater name resolution & search matching + // --------------------------------------------------------------------------- + + /// Resolve a short repeater ID to known repeater names via prefix matching. + static ({List names, bool ambiguous}) _resolveRepeaterNames( + String repeaterId, List repeaters, + ) { + final idLower = repeaterId.toLowerCase(); + final matches = repeaters + .where((r) => r.hexId.toLowerCase().startsWith(idLower)) + .map((r) => r.name) + .toList(); + return (names: matches, ambiguous: matches.length > 1); + } + + /// Whether a hex ID has ambiguous name matches (maps to multiple repeaters). + static bool _isAmbiguousId(String repeaterId, List repeaters) { + return _resolveRepeaterNames(repeaterId, repeaters).ambiguous; + } + + /// True if the query looks like a hex string (only 0-9, a-f). + static bool _isHexQuery(String query) { + return RegExp(r'^[0-9a-fA-F]+$').hasMatch(query); + } + + /// Whether an entry matches the current search query. + bool _matchesSearch(UnifiedPingLogEntry entry, List repeaters) { + if (_searchQuery.isEmpty) return true; + final query = _searchQuery.toLowerCase(); + + switch (entry.type) { + case PingLogType.tx: + final tx = entry.asTx; + for (final event in tx.events) { + if (event.repeaterId.toLowerCase().startsWith(query)) return true; + final resolved = _resolveRepeaterNames(event.repeaterId, repeaters); + if (resolved.names.any((n) => n.toLowerCase().contains(query))) return true; + } + return false; + case PingLogType.rx: + final rx = entry.asRx; + if (rx.repeaterId.toLowerCase().startsWith(query)) return true; + final resolved = _resolveRepeaterNames(rx.repeaterId, repeaters); + return resolved.names.any((n) => n.toLowerCase().contains(query)); + case PingLogType.disc: + final disc = entry.asDisc; + for (final node in disc.discoveredNodes) { + if (node.repeaterId.toLowerCase().startsWith(query)) return true; + if (node.pubkeyHex != null && node.pubkeyHex!.toLowerCase().startsWith(query)) return true; + final resolved = _resolveRepeaterNames(node.repeaterId, repeaters); + if (resolved.names.any((n) => n.toLowerCase().contains(query))) return true; + } + return false; + case PingLogType.trace: + final trace = entry.asTrace; + if (trace.targetRepeaterId.toLowerCase().startsWith(query)) return true; + final resolved = _resolveRepeaterNames(trace.targetRepeaterId, repeaters); + return resolved.names.any((n) => n.toLowerCase().contains(query)); + } + } + + /// Whether an entry should show the ambiguity indicator. + /// Only shown when searching by name (non-hex query) and a repeater ID is ambiguous. + bool _shouldShowAmbiguity(UnifiedPingLogEntry entry, List repeaters) { + if (_searchQuery.isEmpty || _isHexQuery(_searchQuery)) return false; + + switch (entry.type) { + case PingLogType.tx: + return entry.asTx.events.any((e) => _isAmbiguousId(e.repeaterId, repeaters)); + case PingLogType.rx: + return _isAmbiguousId(entry.asRx.repeaterId, repeaters); + case PingLogType.disc: + return entry.asDisc.discoveredNodes.any((n) => _isAmbiguousId(n.repeaterId, repeaters)); + case PingLogType.trace: + return _isAmbiguousId(entry.asTrace.targetRepeaterId, repeaters); + } + } + @override Widget build(BuildContext context) { final filtered = widget.allEntries .where((e) => _activeFilters.contains(e.type)) + .where((e) => _matchesSearch(e, widget.repeaters)) .toList(); + _filteredEntries = filtered; + + final hasEntries = widget.allEntries.isNotEmpty; + final hasResults = filtered.isNotEmpty; return Column( children: [ + // Search bar + Padding( + padding: const EdgeInsets.fromLTRB(12, 4, 12, 0), + child: SizedBox( + height: 36, + child: TextField( + controller: _searchController, + style: const TextStyle(fontSize: 13), + decoration: InputDecoration( + hintText: 'Search by repeater name or ID', + hintStyle: const TextStyle(fontSize: 13), + prefixIcon: const Icon(Icons.search, size: 18), + prefixIconConstraints: const BoxConstraints(minWidth: 36), + suffixIcon: _searchQuery.isNotEmpty + ? GestureDetector( + onTap: () { + _searchController.clear(); + setState(() => _searchQuery = ''); + }, + child: const Icon(Icons.close, size: 18), + ) + : null, + suffixIconConstraints: const BoxConstraints(minWidth: 36), + isDense: true, + contentPadding: const EdgeInsets.symmetric(vertical: 8), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3)), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3)), + ), + ), + onChanged: (value) => setState(() => _searchQuery = value.trim()), + ), + ), + ), // Filter segmented row Padding( padding: const EdgeInsets.fromLTRB(12, 4, 12, 0), @@ -284,14 +448,23 @@ class _AllPingsTabState extends State<_AllPingsTab> { ), // List Expanded( - child: filtered.isEmpty + child: !hasResults ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.list_alt, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant), + Icon( + hasEntries ? Icons.search_off : Icons.list_alt, + size: 48, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), const SizedBox(height: 16), - Text('No pings logged yet', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), + Text( + hasEntries && _searchQuery.isNotEmpty + ? 'No results for \'$_searchQuery\'' + : 'No pings logged yet', + style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), + ), ], ), ) @@ -300,11 +473,12 @@ class _AllPingsTabState extends State<_AllPingsTab> { itemCount: filtered.length, itemBuilder: (context, index) { final unified = filtered[index]; + final showAmbiguity = _shouldShowAmbiguity(unified, widget.repeaters); return switch (unified.type) { - PingLogType.tx => _buildTxCard(context, unified.asTx), - PingLogType.rx => _buildRxCard(context, unified.asRx), - PingLogType.disc => _buildDiscCard(context, unified.asDisc), - PingLogType.trace => _buildTraceCard(context, unified.asTrace), + PingLogType.tx => _buildTxCard(context, unified.asTx, showAmbiguity: showAmbiguity), + PingLogType.rx => _buildRxCard(context, unified.asRx, showAmbiguity: showAmbiguity), + PingLogType.disc => _buildDiscCard(context, unified.asDisc, showAmbiguity: showAmbiguity), + PingLogType.trace => _buildTraceCard(context, unified.asTrace, showAmbiguity: showAmbiguity), }; }, ), @@ -422,7 +596,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { // TX Card // --------------------------------------------------------------------------- - Widget _buildTxCard(BuildContext context, TxLogEntry entry) { + Widget _buildTxCard(BuildContext context, TxLogEntry entry, {bool showAmbiguity = false}) { final appState = context.read(); return Card( margin: const EdgeInsets.only(bottom: 8), @@ -434,7 +608,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildCardHeader(context, PingLogType.tx, entry.timeString, entry.locationString), + _buildCardHeader(context, PingLogType.tx, entry.timeString, entry.locationString, showAmbiguity: showAmbiguity), // Repeaters table if (entry.events.isNotEmpty) ...[ const SizedBox(height: 10), @@ -505,7 +679,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { // RX Card // --------------------------------------------------------------------------- - Widget _buildRxCard(BuildContext context, RxLogEntry entry) { + Widget _buildRxCard(BuildContext context, RxLogEntry entry, {bool showAmbiguity = false}) { final appState = context.read(); final snrColor = _snrColor(entry.severity); final rssiColor = _rssiColor(entry.rssi); @@ -520,7 +694,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildCardHeader(context, PingLogType.rx, entry.timeString, entry.locationString), + _buildCardHeader(context, PingLogType.rx, entry.timeString, entry.locationString, showAmbiguity: showAmbiguity), const SizedBox(height: 10), // Repeater table (single row) Container( @@ -569,7 +743,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { // DISC Card // --------------------------------------------------------------------------- - Widget _buildDiscCard(BuildContext context, DiscLogEntry entry) { + Widget _buildDiscCard(BuildContext context, DiscLogEntry entry, {bool showAmbiguity = false}) { final appState = context.read(); return Card( @@ -582,7 +756,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildCardHeader(context, PingLogType.disc, entry.timeString, entry.locationString), + _buildCardHeader(context, PingLogType.disc, entry.timeString, entry.locationString, showAmbiguity: showAmbiguity), // Nodes table if (entry.discoveredNodes.isNotEmpty) ...[ const SizedBox(height: 10), @@ -675,7 +849,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { // Trace Card // --------------------------------------------------------------------------- - Widget _buildTraceCard(BuildContext context, TraceLogEntry entry) { + Widget _buildTraceCard(BuildContext context, TraceLogEntry entry, {bool showAmbiguity = false}) { final colorScheme = Theme.of(context).colorScheme; final appState = context.read(); @@ -689,7 +863,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildCardHeader(context, PingLogType.trace, entry.timeString, entry.locationString), + _buildCardHeader(context, PingLogType.trace, entry.timeString, entry.locationString, showAmbiguity: showAmbiguity), // Results table if (entry.success) ...[ const SizedBox(height: 10), @@ -757,10 +931,17 @@ class _AllPingsTabState extends State<_AllPingsTab> { // Shared helpers // --------------------------------------------------------------------------- - static Widget _buildCardHeader(BuildContext context, PingLogType type, String timeString, String locationString) { + static Widget _buildCardHeader(BuildContext context, PingLogType type, String timeString, String locationString, {bool showAmbiguity = false}) { return Row( children: [ _buildTypeBadge(type), + if (showAmbiguity) ...[ + const SizedBox(width: 2), + Tooltip( + message: 'Repeater ID matches multiple nodes', + child: Icon(Icons.help_outline, size: 14, color: Colors.amber.shade700), + ), + ], const SizedBox(width: 6), Text( timeString, diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index e6332d5..9c26a4a 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -107,801 +107,770 @@ class _SettingsScreenState extends State { automaticallyImplyLeading: false, ), body: ListView( + padding: const EdgeInsets.fromLTRB(12, 8, 12, 24), children: [ - // Appearance section - _buildSectionHeader(context, 'Appearance'), - SwitchListTile( - secondary: Icon( - prefs.themeMode == 'dark' ? Icons.dark_mode : Icons.light_mode, - ), - title: const Text('Theme'), - subtitle: Text(prefs.themeMode == 'dark' ? 'Dark mode' : 'Light mode'), - value: prefs.themeMode == 'dark', - onChanged: (isDark) { - appState.setThemeMode(isDark ? 'dark' : 'light'); - }, - ), - SwitchListTile( - secondary: Icon( - prefs.isImperial ? Icons.square_foot : Icons.straighten, - ), - title: const Text('Units'), - subtitle: Text(prefs.isImperial ? 'Imperial (mi, ft)' : 'Metric (km, m)'), - value: prefs.isImperial, - onChanged: (isImperial) { - appState.setUnitSystem(isImperial ? 'imperial' : 'metric'); - }, - ), - - const Divider(), - - // Wardriving Settings section - _buildSectionHeader(context, 'Wardriving Settings'), - - // Sound Notifications Toggle - SwitchListTile( - secondary: Icon(appState.isSoundEnabled ? Icons.volume_up : Icons.volume_off), - title: const Text('Sound Notifications'), - subtitle: Text(appState.isSoundEnabled ? 'Plays on ping events' : 'Silent'), - value: appState.isSoundEnabled, - onChanged: (_) => appState.toggleSoundEnabled(), - ), - - // Auto-Ping Interval Selector - ListTile( - leading: const Icon(Icons.timer), - title: const Text('Auto-Ping Interval'), - subtitle: Text(prefs.autoPingIntervalDisplay), - trailing: const Icon(Icons.chevron_right), - enabled: !isAutoMode, - onTap: isAutoMode ? null : () => _showIntervalSelector(context, appState), - ), - - // Min Ping Distance Selector - ListTile( - leading: const Icon(Icons.straighten), - title: const Text('Min Ping Distance'), - subtitle: Text(prefs.minPingDistanceDisplay), - trailing: const Icon(Icons.chevron_right), - enabled: !isAutoMode, - onTap: isAutoMode ? null : () => _showDistanceSelector(context, appState), - ), - - // Auto-Stop After Idle Toggle - SwitchListTile( - secondary: const Icon(Icons.timer_off), - title: const Text('Auto-Stop After Idle'), - subtitle: const Text('Stops auto-ping after 30 min without movement'), - value: prefs.autoStopAfterIdle, - onChanged: isAutoMode ? null : (value) { - appState.updatePreferences(prefs.copyWith(autoStopAfterIdle: value)); - }, - ), - - // Hybrid Mode Toggle - SwitchListTile( - secondary: const Icon(Icons.compare_arrows), - title: Row( - children: [ - const Flexible(child: Text('Hybrid Mode', overflow: TextOverflow.ellipsis)), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _showHybridModeInfo(context), - child: Icon( - Icons.info_outline, - size: 18, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), + // Lock indicator + if (isAutoMode) + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.amber.withValues(alpha: 0.12), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.amber.withValues(alpha: 0.3)), ), - ], - ), - subtitle: appState.enforceHybrid - ? const Text( - 'Set by Regional Admin — hybrid uses 50% fewer flood packets, improving mesh health.', - style: TextStyle(color: Colors.amber), - ) - : const Text('Combines Active and Passive modes'), - value: appState.enforceHybrid ? true : prefs.hybridModeEnabled, - onChanged: (isAutoMode || appState.enforceHybrid) ? null : (value) { - appState.updatePreferences(prefs.copyWith(hybridModeEnabled: value)); - }, - ), - - // Discovery Drop Toggle - SwitchListTile( - secondary: const Icon(Icons.signal_wifi_off), - title: Row( - children: [ - const Flexible(child: Text('Discovery Drop', overflow: TextOverflow.ellipsis)), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _showDiscDropInfo(context), - child: Icon( - Icons.info_outline, - size: 18, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), + child: const Row( + children: [ + Icon(Icons.lock, size: 16, color: Colors.amber), + SizedBox(width: 8), + Text( + 'Some settings locked during auto-ping', + style: TextStyle(fontSize: 12, color: Colors.amber), + ), + ], ), - ], + ), ), - subtitle: appState.enforceDiscDrop - ? const Text( - 'Set by Regional Admin — reports dead zones for network analysis.', - style: TextStyle(color: Colors.amber), - ) - : const Text('Count failed discoveries as failed pings'), - value: appState.enforceDiscDrop ? true : prefs.discDropEnabled, - onChanged: (isAutoMode || appState.enforceDiscDrop) ? null : (value) { - appState.updatePreferences(prefs.copyWith(discDropEnabled: value)); - }, - ), - // CARpeater Filter Setting - SwitchListTile( - secondary: const Icon(Icons.filter_alt), - title: const Text('CARpeater Filter'), - subtitle: Text(prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null - ? 'Pass-through: stripping 0x${prefs.ignoreRepeaterId}' - : 'Tap to set CARpeater repeater ID'), - value: prefs.ignoreCarpeater, - onChanged: isAutoMode ? null : (value) { - if (value && prefs.ignoreRepeaterId == null) { - // Show dialog to set repeater ID when enabling - _showRepeaterIdDialog(context, appState); - } else { - appState.updatePreferences(prefs.copyWith(ignoreCarpeater: value)); - } - }, - ), + // General + _buildSection(context, 'General', [ + SwitchListTile( + secondary: Icon( + prefs.themeMode == 'dark' ? Icons.dark_mode : Icons.light_mode, + ), + title: const Text('Theme'), + subtitle: Text(prefs.themeMode == 'dark' ? 'Dark mode' : 'Light mode'), + value: prefs.themeMode == 'dark', + onChanged: (isDark) { + appState.setThemeMode(isDark ? 'dark' : 'light'); + }, + ), + SwitchListTile( + secondary: Icon( + prefs.isImperial ? Icons.square_foot : Icons.straighten, + ), + title: const Text('Units'), + subtitle: Text(prefs.isImperial ? 'Imperial (mi, ft)' : 'Metric (km, m)'), + value: prefs.isImperial, + onChanged: (isImperial) { + appState.setUnitSystem(isImperial ? 'imperial' : 'metric'); + }, + ), + if (!kIsWeb) + _BackgroundModeToggle(appState: appState), + ]), - // CARpeater ID - show when enabled - if (prefs.ignoreCarpeater) + // Ping Settings + _buildSection(context, 'Ping Settings', [ + SwitchListTile( + secondary: const Icon(Icons.visibility_off), + title: const Text('Anonymous Mode'), + subtitle: Text(prefs.anonymousMode + ? 'Device broadcasts as "Anonymous"' + : 'Device uses its real name'), + value: prefs.anonymousMode, + onChanged: isAutoMode ? null : (value) { + if (value) { + _showEnableAnonymousConfirmation(context, appState); + } else { + if (appState.connectionStatus == ConnectionStatus.connected) { + _showDisableAnonymousConfirmation(context, appState); + } else { + appState.setAnonymousMode(false); + } + } + }, + ), ListTile( - leading: const SizedBox(width: 24), // Indent - title: const Text('CARpeater ID'), - subtitle: Text(prefs.ignoreRepeaterId != null - ? '0x${prefs.ignoreRepeaterId}' - : 'Not set'), + leading: const Icon(Icons.timer), + title: const Text('Auto-Ping Interval'), + subtitle: Text(prefs.autoPingIntervalDisplay), trailing: const Icon(Icons.chevron_right), enabled: !isAutoMode, - onTap: isAutoMode ? null : () => _showRepeaterIdDialog(context, appState), + onTap: isAutoMode ? null : () => _showIntervalSelector(context, appState), ), + ListTile( + leading: const Icon(Icons.straighten), + title: const Text('Min Ping Distance'), + subtitle: Text(prefs.minPingDistanceDisplay), + trailing: const Icon(Icons.chevron_right), + enabled: !isAutoMode, + onTap: isAutoMode ? null : () => _showDistanceSelector(context, appState), + ), + SwitchListTile( + secondary: Icon(appState.isSoundEnabled ? Icons.volume_up : Icons.volume_off), + title: const Text('Sound Notifications'), + subtitle: Text(appState.isSoundEnabled ? 'Plays on ping events' : 'Silent'), + value: appState.isSoundEnabled, + onChanged: (_) => appState.toggleSoundEnabled(), + ), + SwitchListTile( + secondary: const Icon(Icons.timer_off), + title: const Text('Auto-Stop After Idle'), + subtitle: const Text('Stops auto-ping after 30 min without movement'), + value: prefs.autoStopAfterIdle, + onChanged: isAutoMode ? null : (value) { + appState.updatePreferences(prefs.copyWith(autoStopAfterIdle: value)); + }, + ), + ]), - // Anonymous Mode Toggle - SwitchListTile( - secondary: const Icon(Icons.visibility_off), - title: const Text('Anonymous Mode'), - subtitle: Text(prefs.anonymousMode - ? 'Device broadcasts as "Anonymous"' - : 'Device uses its real name'), - value: prefs.anonymousMode, - onChanged: isAutoMode ? null : (value) { - if (value) { - _showEnableAnonymousConfirmation(context, appState); - } else { - if (appState.connectionStatus == ConnectionStatus.connected) { - _showDisableAnonymousConfirmation(context, appState); - } else { - appState.setAnonymousMode(false); - } - } - }, - ), - - // Delete Channel on Disconnect Toggle - SwitchListTile( - secondary: const Icon(Icons.delete_sweep), - title: const Text('Delete Channel on Disconnect'), - subtitle: const Text('Remove #wardriving channel from radio when disconnecting'), - value: prefs.deleteChannelOnDisconnect, - onChanged: (value) { - appState.updatePreferences(prefs.copyWith(deleteChannelOnDisconnect: value)); - }, - ), - - // Disable RSSI Filter Toggle - SwitchListTile( - secondary: const Icon(Icons.shield_outlined), - title: const Text('Disable RSSI Filter'), - subtitle: Text(prefs.disableRssiFilter - ? 'Allows all signal strengths' - : 'Drops signals stronger than -30 dBm'), - value: prefs.disableRssiFilter, - onChanged: isAutoMode ? null : (value) { - if (value) { - _showDisableRssiFilterConfirmation(context, appState); - } else { - appState.updatePreferences(prefs.copyWith(disableRssiFilter: false)); - } - }, - ), - - // Lock indicator - if (isAutoMode) - const Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Row( + // Modes + _buildSection(context, 'Modes', [ + SwitchListTile( + secondary: const Icon(Icons.compare_arrows), + title: Row( children: [ - Icon(Icons.lock, size: 16, color: Colors.amber), - SizedBox(width: 8), - Expanded( - child: Text( - 'Settings locked during auto-ping mode', - style: TextStyle( - fontSize: 12, - color: Colors.amber, - ), + const Flexible(child: Text('Hybrid Mode', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showHybridModeInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), + subtitle: appState.enforceHybrid + ? const Text( + 'Set by Regional Admin — hybrid uses 50% fewer flood packets, improving mesh health.', + style: TextStyle(color: Colors.amber), + ) + : const Text('Combines Active and Passive modes'), + value: appState.enforceHybrid ? true : prefs.hybridModeEnabled, + onChanged: (isAutoMode || appState.enforceHybrid) ? null : (value) { + appState.updatePreferences(prefs.copyWith(hybridModeEnabled: value)); + }, ), - - // Radio Settings section - const Divider(), - _buildSectionHeader(context, 'Radio Settings'), - - // TX Bytes Setting - ListTile( - leading: const Icon(Icons.linear_scale), - title: Row( - children: [ - const Flexible(child: Text('TX Bytes', overflow: TextOverflow.ellipsis)), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _showHopBytesInfo(context), - child: Icon( - Icons.info_outline, - size: 18, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ], - ), - subtitle: appState.enforceHopBytes - ? const Text( - 'Set by Regional Admin — larger IDs reduce collisions in your region.', - style: TextStyle(color: Colors.amber), - ) - : (appState.isConnected && !appState.supportsMultiBytePaths) - ? const Text( - 'Firmware 1.14+ required', - style: TextStyle(color: Colors.amber), - ) - : !appState.isConnected - ? const Text( - 'Connect to radio to configure', - style: TextStyle(color: Colors.amber), - ) - : const Text('Repeater ID size in TX/RX path hops'), - trailing: DropdownButton( - value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, - underline: const SizedBox(), - items: const [ - DropdownMenuItem(value: 1, child: Text('1')), - DropdownMenuItem(value: 2, child: Text('2')), - DropdownMenuItem(value: 3, child: Text('3')), - ], - onChanged: (!appState.isConnected || isAutoMode || appState.enforceHopBytes || !appState.supportsMultiBytePaths) - ? null - : (value) { - if (value != null) appState.setHopBytes(value); - }, - ), - ), - - // Trace Bytes Setting - ListTile( - leading: const Icon(Icons.gps_fixed), - title: Row( - children: [ - const Flexible(child: Text('Trace Bytes', overflow: TextOverflow.ellipsis)), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _showTraceBytesInfo(context), - child: Icon( - Icons.info_outline, - size: 18, - color: Theme.of(context).colorScheme.onSurfaceVariant, + SwitchListTile( + secondary: const Icon(Icons.signal_wifi_off), + title: Row( + children: [ + const Flexible(child: Text('Discovery Drop', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showDiscDropInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ), - ), - ], - ), - subtitle: !appState.isConnected - ? const Text( - 'Connect to radio to configure', - style: TextStyle(color: Colors.amber), - ) - : (appState.isConnected && !appState.supportsMultiBytePaths) - ? const Text( - 'Firmware 1.14+ required', - style: TextStyle(color: Colors.amber), - ) - : const Text('Repeater ID size in trace path'), - trailing: DropdownButton( - value: appState.traceHopBytes, - underline: const SizedBox(), - items: const [ - DropdownMenuItem(value: 1, child: Text('1')), - DropdownMenuItem(value: 2, child: Text('2')), - DropdownMenuItem(value: 4, child: Text('4')), - ], - onChanged: (!appState.isConnected || isAutoMode || !appState.supportsMultiBytePaths) - ? null - : (value) { - if (value != null) appState.setTraceHopBytes(value); - }, - ), - ), - - // Background Mode - for "Always" location permission (iOS and Android) - if (!kIsWeb) ...[ - const Divider(), - _buildSectionHeader(context, 'Background Mode'), - _BackgroundModeToggle(appState: appState), - ], - - const Divider(), - - // Data Management section - _buildSectionHeader(context, 'Data Management'), - ListTile( - leading: const Icon(Icons.cloud_queue), - title: const Text('Queued Pings'), - subtitle: Text('${appState.queueSize} items waiting'), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.cloud_upload), - onPressed: appState.queueSize > 0 - ? () => appState.forceUploadQueue() - : null, - tooltip: 'Force upload', - ), - IconButton( - icon: const Icon(Icons.delete_outline), - onPressed: appState.queueSize > 0 - ? () => _confirmClearQueue(context, appState) - : null, - tooltip: 'Clear queue', - ), - ], - ), - ), - - // Clear Map Markers - ListTile( - leading: const Icon(Icons.delete_sweep), - title: const Text('Clear Map Markers'), - subtitle: const Text('Remove all TX/RX markers from map'), - onTap: () => _confirmClearPings(context, appState), - ), - - // Offline Sessions - _buildSectionHeader(context, 'Offline Sessions'), - if (appState.offlineSessions.isEmpty) - ListTile( - leading: Icon(Icons.cloud_off, color: Colors.grey.shade400), - title: Text( - 'No offline sessions stored', - style: TextStyle(color: Colors.grey.shade500), - ), - subtitle: Text( - 'Sessions recorded in offline mode will appear here for upload', - style: TextStyle(fontSize: 12, color: Colors.grey.shade400), + ], ), - ) - else - ...appState.offlineSessions.map((session) => _OfflineSessionTile( - session: session, - onUpload: () => _uploadOfflineSession(context, appState, session.filename), - onDelete: () => _confirmDeleteOfflineSession(context, appState, session.filename), - onDownload: () => _downloadOfflineSession(context, appState, session.filename), - )), - - const Divider(), - - // About section - _buildSectionHeader(context, 'About'), - ListTile( - leading: const Icon(Icons.perm_identity), - title: const Text('Device ID'), - subtitle: Text(appState.deviceId), - ), - const ListTile( - leading: Icon(Icons.info_outline), - title: Text(AppConstants.appName), - subtitle: Text('Mesh network coverage mapper'), - ), - ListTile( - leading: const Icon(Icons.new_releases_outlined), - title: const Text('Version'), - subtitle: Text(AppConstants.appVersion), - onTap: () => _onVersionTap(appState), - ), - ListTile( - leading: const Icon(Icons.feedback_outlined), - title: const Text('Submit Feedback'), - subtitle: const Text('Report bugs or request features'), - onTap: () => _showBugReportDialog(context, appState), - ), - ListTile( - leading: const FaIcon(FontAwesomeIcons.github), - title: const Text('GitHub'), - subtitle: const Text('View issues and source code'), - onTap: () => _launchUrl('https://github.com/MeshMapper/MeshMapper_Project'), - ), - ListTile( - leading: const FaIcon(FontAwesomeIcons.discord), - title: const Text('Discord'), - subtitle: const Text('Join our community chat'), - onTap: () => _launchUrl('https://discord.gg/D26P6c6QmG'), - ), - ListTile( - leading: const Icon(Icons.groups), - title: const Text('Community'), - subtitle: const Text('Built with contributions from the Greater Ottawa Mesh Radio Enthusiasts community'), - onTap: () => _launchUrl('https://ottawamesh.ca/'), - ), - ListTile( - leading: const Icon(Icons.coffee), - title: const Text('Buy us a coffee ☕'), - subtitle: const Text('Support MeshMapper development'), - onTap: () => _launchUrl('https://buymeacoffee.com/meshmapper'), - ), - - // Exit Options (Android only) - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) ...[ - const Divider(), - _buildSectionHeader(context, 'Exit Options'), - - // Auto-close toggle - SwitchListTile( - secondary: const Icon(Icons.exit_to_app), - title: const Text('Close App After Disconnect'), - subtitle: const Text('Automatically exit the app when disconnecting'), - value: prefs.closeAppAfterDisconnect, - onChanged: (value) => appState.setCloseAppAfterDisconnect(value), + subtitle: appState.enforceDiscDrop + ? const Text( + 'Set by Regional Admin — reports dead zones for network analysis.', + style: TextStyle(color: Colors.amber), + ) + : const Text('Count failed discoveries as failed pings'), + value: appState.enforceDiscDrop ? true : prefs.discDropEnabled, + onChanged: (isAutoMode || appState.enforceDiscDrop) ? null : (value) { + appState.updatePreferences(prefs.copyWith(discDropEnabled: value)); + }, ), + ]), - // Manual close button - ListTile( - leading: const Icon(Icons.power_settings_new, color: Colors.red), - title: const Text('Close App'), - subtitle: const Text('Exit the app completely'), - onTap: () => _showCloseAppConfirmation(context, appState), + // Filtering + _buildSection(context, 'Filtering', [ + SwitchListTile( + secondary: const Icon(Icons.filter_alt), + title: const Text('CARpeater Filter'), + subtitle: Text(prefs.ignoreCarpeater && prefs.ignoreRepeaterId != null + ? 'Pass-through: stripping 0x${prefs.ignoreRepeaterId}' + : 'Tap to set CARpeater repeater ID'), + value: prefs.ignoreCarpeater, + onChanged: isAutoMode ? null : (value) { + if (value && prefs.ignoreRepeaterId == null) { + _showRepeaterIdDialog(context, appState); + } else { + appState.updatePreferences(prefs.copyWith(ignoreCarpeater: value)); + } + }, ), - ], - - // Developer Tools section - only visible when developer mode is enabled - if (appState.developerModeEnabled) ...[ - const Divider(), - - _buildSectionHeader(context, 'Developer Tools'), - - // Developer mode toggle (to disable) + if (prefs.ignoreCarpeater) + ListTile( + leading: const SizedBox(width: 24), + title: const Text('CARpeater ID'), + subtitle: Text(prefs.ignoreRepeaterId != null + ? '0x${prefs.ignoreRepeaterId}' + : 'Not set'), + trailing: const Icon(Icons.chevron_right), + enabled: !isAutoMode, + onTap: isAutoMode ? null : () => _showRepeaterIdDialog(context, appState), + ), SwitchListTile( - secondary: const Icon(Icons.developer_mode), - title: const Text('Developer Mode'), - subtitle: const Text('Disable to hide developer tools'), - value: appState.developerModeEnabled, - onChanged: (value) { - appState.setDeveloperMode(value); + secondary: const Icon(Icons.shield_outlined), + title: const Text('Disable RSSI Filter'), + subtitle: Text(prefs.disableRssiFilter + ? 'Allows all signal strengths' + : 'Drops signals stronger than -30 dBm'), + value: prefs.disableRssiFilter, + onChanged: isAutoMode ? null : (value) { + if (value) { + _showDisableRssiFilterConfirmation(context, appState); + } else { + appState.updatePreferences(prefs.copyWith(disableRssiFilter: false)); + } }, ), + ]), - // GPS Simulator Toggle - SwitchListTile( - secondary: Icon( - Icons.gps_fixed, - color: appState.isGpsSimulatorEnabled ? Colors.orange : null, - ), - title: Row( - children: [ - const Text('GPS Simulator'), - if (appState.isGpsSimulatorEnabled) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.orange, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'SIMULATED', - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.bold, - color: Colors.white, - ), + // Radio Settings + _buildSection(context, 'Radio', [ + ListTile( + leading: const Icon(Icons.linear_scale), + title: Row( + children: [ + const Flexible(child: Text('TX Bytes', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showHopBytesInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], - ], - ), - subtitle: Text(appState.isGpsSimulatorEnabled - ? 'Smooth simulated movement active' - : 'Use simulated GPS for testing'), - value: appState.isGpsSimulatorEnabled, - onChanged: (value) { - if (value) { - appState.enableGpsSimulator(); - } else { - appState.disableGpsSimulator(); - } - }, - ), - - // Simulator Settings (only when enabled) - if (appState.isGpsSimulatorEnabled) ...[ - // Speed Slider - ListTile( - leading: const SizedBox(width: 24), - title: const Text('Simulation Speed'), - subtitle: Slider( - value: appState.gpsSimulatorSpeed, - min: 10, - max: 120, - divisions: 11, - label: formatSpeed(appState.gpsSimulatorSpeed, isImperial: prefs.isImperial), - onChanged: (value) { - appState.setGpsSimulatorSpeed(value); - }, ), - trailing: Text( - formatSpeed(appState.gpsSimulatorSpeed, isImperial: prefs.isImperial), - style: const TextStyle(fontWeight: FontWeight.bold), + subtitle: appState.enforceHopBytes + ? const Text( + 'Set by Regional Admin — larger IDs reduce collisions in your region.', + style: TextStyle(color: Colors.amber), + ) + : (appState.isConnected && !appState.supportsMultiBytePaths) + ? const Text( + 'Firmware 1.14+ required', + style: TextStyle(color: Colors.amber), + ) + : !appState.isConnected + ? const Text( + 'Connect to radio to configure', + style: TextStyle(color: Colors.amber), + ) + : const Text('Repeater ID size in TX/RX path hops'), + trailing: DropdownButton( + value: appState.enforceHopBytes ? appState.effectiveHopBytes : appState.hopBytes, + underline: const SizedBox(), + items: const [ + DropdownMenuItem(value: 1, child: Text('1')), + DropdownMenuItem(value: 2, child: Text('2')), + DropdownMenuItem(value: 3, child: Text('3')), + ], + onChanged: (!appState.isConnected || isAutoMode || appState.enforceHopBytes || !appState.supportsMultiBytePaths) + ? null + : (value) { + if (value != null) appState.setHopBytes(value); + }, ), ), - - // Pattern Selector ListTile( - leading: const SizedBox(width: 24), - title: const Text('Movement Pattern'), - trailing: SizedBox( - width: 180, - child: DropdownButton( - value: appState.gpsSimulatorPattern, - underline: const SizedBox(), - isExpanded: true, - items: [ - const DropdownMenuItem( - value: SimulatorPattern.straight, - child: Text('Straight Line', overflow: TextOverflow.ellipsis), - ), - const DropdownMenuItem( - value: SimulatorPattern.circle, - child: Text('Circle', overflow: TextOverflow.ellipsis), + leading: const Icon(Icons.gps_fixed), + title: Row( + children: [ + const Flexible(child: Text('Trace Bytes', overflow: TextOverflow.ellipsis)), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showTraceBytesInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), - const DropdownMenuItem( - value: SimulatorPattern.randomWalk, - child: Text('Random Walk', overflow: TextOverflow.ellipsis), + ), + ], + ), + subtitle: !appState.isConnected + ? const Text( + 'Connect to radio to configure', + style: TextStyle(color: Colors.amber), + ) + : (appState.isConnected && !appState.supportsMultiBytePaths) + ? const Text( + 'Firmware 1.14+ required', + style: TextStyle(color: Colors.amber), + ) + : const Text('Repeater ID size in trace path'), + trailing: DropdownButton( + value: appState.traceHopBytes, + underline: const SizedBox(), + items: const [ + DropdownMenuItem(value: 1, child: Text('1')), + DropdownMenuItem(value: 2, child: Text('2')), + DropdownMenuItem(value: 4, child: Text('4')), + ], + onChanged: (!appState.isConnected || isAutoMode || !appState.supportsMultiBytePaths) + ? null + : (value) { + if (value != null) appState.setTraceHopBytes(value); + }, + ), + ), + SwitchListTile( + secondary: const Icon(Icons.delete_sweep), + title: Row( + children: [ + const Flexible(child: Text('Delete Channel on Disconnect')), + const SizedBox(width: 4), + GestureDetector( + onTap: () => _showDeleteChannelInfo(context), + child: Icon( + Icons.info_outline, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), - if (appState.hasSimulatorRoute) - DropdownMenuItem( - value: SimulatorPattern.route, - child: Text( - 'Route: ${appState.simulatorRouteName ?? "Loaded"}', - overflow: TextOverflow.ellipsis, - ), - ), - ], - onChanged: (pattern) { - if (pattern != null) { - appState.setGpsSimulatorPattern(pattern); - } - }, - ), + ), + ], ), + value: prefs.deleteChannelOnDisconnect, + onChanged: (value) { + appState.updatePreferences(prefs.copyWith(deleteChannelOnDisconnect: value)); + }, ), + ]), - // Load Route File + // Data Management + _buildSection(context, 'Data', [ ListTile( - leading: const SizedBox(width: 24), - title: const Text('Load Route File'), - subtitle: Text(appState.hasSimulatorRoute - ? '${appState.simulatorRouteName} (${appState.simulatorRoutePointCount} points)' - : 'KML or GPX file'), + leading: const Icon(Icons.cloud_queue), + title: const Text('Queued Pings'), + subtitle: Text('${appState.queueSize} items waiting'), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( - icon: const Icon(Icons.folder_open), - onPressed: () => _pickRouteFile(context, appState), - tooltip: 'Load route file', + icon: const Icon(Icons.cloud_upload), + onPressed: appState.queueSize > 0 + ? () => appState.forceUploadQueue() + : null, + tooltip: 'Force upload', + ), + IconButton( + icon: const Icon(Icons.delete_outline), + onPressed: appState.queueSize > 0 + ? () => _confirmClearQueue(context, appState) + : null, + tooltip: 'Clear queue', ), - if (appState.hasSimulatorRoute) - IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - appState.clearSimulatorRoute(); - AppToast.info(context, 'Route cleared'); - }, - tooltip: 'Clear route', - ), ], ), ), - - // Reset Position Button ListTile( - leading: const SizedBox(width: 24), - title: const Text('Reset Position'), - subtitle: Text(appState.hasSimulatorRoute - ? 'Reset to route start' - : 'Reset to Ottawa downtown'), - trailing: IconButton( - icon: const Icon(Icons.restart_alt), - onPressed: () { - appState.resetGpsSimulator(); - AppToast.info( - context, - appState.hasSimulatorRoute - ? 'Reset to route start' - : 'GPS simulator reset to Ottawa downtown', - ); - }, - ), + leading: const Icon(Icons.delete_sweep), + title: const Text('Clear Map Markers'), + subtitle: const Text('Remove all TX/RX markers from map'), + onTap: () => _confirmClearPings(context, appState), ), - ], - ], // Close developerModeEnabled conditional + ]), - // Debug section (always visible on mobile) - if (!kIsWeb) ...[ - const Divider(), - - _buildSectionHeader(context, 'Debug'), + // Offline Sessions + _buildSection(context, 'Offline Sessions', [ + if (appState.offlineSessions.isEmpty) + ListTile( + leading: Icon(Icons.cloud_off, color: Colors.grey.shade400), + title: Text( + 'No offline sessions stored', + style: TextStyle(color: Colors.grey.shade500), + ), + subtitle: Text( + 'Sessions recorded in offline mode will appear here', + style: TextStyle(fontSize: 12, color: Colors.grey.shade400), + ), + ) + else + ...appState.offlineSessions.map((session) => _OfflineSessionTile( + session: session, + onUpload: () => _uploadOfflineSession(context, appState, session.filename), + onDelete: () => _confirmDeleteOfflineSession(context, appState, session.filename), + onDownload: () => _downloadOfflineSession(context, appState, session.filename), + )), + ]), + + // About + _buildSection(context, 'About', [ + const ListTile( + leading: Icon(Icons.info_outline), + title: Text(AppConstants.appName), + subtitle: Text('Mesh network coverage mapper'), + ), + ListTile( + leading: const Icon(Icons.new_releases_outlined), + title: const Text('Version'), + subtitle: Text(AppConstants.appVersion), + onTap: () => _onVersionTap(appState), + ), + ListTile( + leading: const Icon(Icons.feedback_outlined), + title: const Text('Submit Feedback'), + subtitle: const Text('Report bugs or request features'), + onTap: () => _showBugReportDialog(context, appState), + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.github), + title: const Text('GitHub'), + subtitle: const Text('View issues and source code'), + onTap: () => _launchUrl('https://github.com/MeshMapper/MeshMapper_Project'), + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.discord), + title: const Text('Discord'), + subtitle: const Text('Join our community chat'), + onTap: () => _launchUrl('https://discord.gg/D26P6c6QmG'), + ), + ListTile( + leading: const Icon(Icons.groups), + title: const Text('Community'), + subtitle: const Text('Built with contributions from the Greater Ottawa Mesh Radio Enthusiasts community'), + onTap: () => _launchUrl('https://ottawamesh.ca/'), + ), + ListTile( + leading: const Icon(Icons.coffee), + title: const Text('Buy us a coffee'), + subtitle: const Text('Support MeshMapper development'), + onTap: () => _launchUrl('https://buymeacoffee.com/meshmapper'), + ), + ]), - SwitchListTile( - secondary: Icon( - Icons.bug_report, - color: appState.debugLogsEnabled ? Colors.orange : null, + // Exit Options (Android only) + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) + _buildSection(context, 'Exit', [ + SwitchListTile( + secondary: const Icon(Icons.exit_to_app), + title: const Text('Close App After Disconnect'), + subtitle: const Text('Automatically exit the app when disconnecting'), + value: prefs.closeAppAfterDisconnect, + onChanged: (value) => appState.setCloseAppAfterDisconnect(value), ), - title: Row( - children: [ - const Text('Debug Logs'), - if (appState.debugLogsEnabled) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.orange, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'LOGGING', - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.bold, - color: Colors.white, + ListTile( + leading: const Icon(Icons.power_settings_new, color: Colors.red), + title: const Text('Close App'), + subtitle: const Text('Exit the app completely'), + onTap: () => _showCloseAppConfirmation(context, appState), + ), + ]), + + // Developer Tools - only visible when developer mode is enabled + if (appState.developerModeEnabled) + _buildSection(context, 'Developer Tools', [ + SwitchListTile( + secondary: const Icon(Icons.developer_mode), + title: const Text('Developer Mode'), + subtitle: const Text('Disable to hide developer tools'), + value: appState.developerModeEnabled, + onChanged: (value) { + appState.setDeveloperMode(value); + }, + ), + SwitchListTile( + secondary: Icon( + Icons.gps_fixed, + color: appState.isGpsSimulatorEnabled ? Colors.orange : null, + ), + title: Row( + children: [ + const Text('GPS Simulator'), + if (appState.isGpsSimulatorEnabled) ...[ + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: Colors.orange, + borderRadius: BorderRadius.circular(4), + ), + child: const Text( + 'SIMULATED', + style: TextStyle( + fontSize: 9, + fontWeight: FontWeight.bold, + color: Colors.white, + ), ), ), - ), + ], ], - ], - ), - subtitle: Text( - appState.debugLogsEnabled - ? 'Writing logs to file' - : 'Enable to save debug logs to device', + ), + subtitle: Text(appState.isGpsSimulatorEnabled + ? 'Smooth simulated movement active' + : 'Use simulated GPS for testing'), + value: appState.isGpsSimulatorEnabled, + onChanged: (value) { + if (value) { + appState.enableGpsSimulator(); + } else { + appState.disableGpsSimulator(); + } + }, ), - value: appState.debugLogsEnabled, - onChanged: (value) async { - if (value) { - await appState.enableDebugLogs(); - } else { - await appState.disableDebugLogs(); - } - }, - ), - - // Log Files List (show when toggle is ON or when files exist) - if (appState.debugLogsEnabled || appState.debugLogFiles.isNotEmpty) ...[ - // Section header with Delete All button - Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), - child: Row( - children: [ - Text( - 'Debug Log Files', - style: Theme.of(context).textTheme.titleSmall?.copyWith( - color: Colors.grey.shade600, + if (appState.isGpsSimulatorEnabled) ...[ + ListTile( + leading: const SizedBox(width: 24), + title: const Text('Simulation Speed'), + subtitle: Slider( + value: appState.gpsSimulatorSpeed, + min: 10, + max: 120, + divisions: 11, + label: formatSpeed(appState.gpsSimulatorSpeed, isImperial: prefs.isImperial), + onChanged: (value) { + appState.setGpsSimulatorSpeed(value); + }, + ), + trailing: Text( + formatSpeed(appState.gpsSimulatorSpeed, isImperial: prefs.isImperial), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ListTile( + leading: const SizedBox(width: 24), + title: const Text('Movement Pattern'), + trailing: SizedBox( + width: 180, + child: DropdownButton( + value: appState.gpsSimulatorPattern, + underline: const SizedBox(), + isExpanded: true, + items: [ + const DropdownMenuItem( + value: SimulatorPattern.straight, + child: Text('Straight Line', overflow: TextOverflow.ellipsis), + ), + const DropdownMenuItem( + value: SimulatorPattern.circle, + child: Text('Circle', overflow: TextOverflow.ellipsis), + ), + const DropdownMenuItem( + value: SimulatorPattern.randomWalk, + child: Text('Random Walk', overflow: TextOverflow.ellipsis), + ), + if (appState.hasSimulatorRoute) + DropdownMenuItem( + value: SimulatorPattern.route, + child: Text( + 'Route: ${appState.simulatorRouteName ?? "Loaded"}', + overflow: TextOverflow.ellipsis, + ), ), + ], + onChanged: (pattern) { + if (pattern != null) { + appState.setGpsSimulatorPattern(pattern); + } + }, ), - const Spacer(), - if (appState.debugLogFiles.isNotEmpty) ...[ - TextButton.icon( - icon: const Icon(Icons.cloud_upload, size: 18), - label: const Text('Upload'), - onPressed: () => _showUploadLogsDialog(context, appState), + ), + ), + ListTile( + leading: const SizedBox(width: 24), + title: const Text('Load Route File'), + subtitle: Text(appState.hasSimulatorRoute + ? '${appState.simulatorRouteName} (${appState.simulatorRoutePointCount} points)' + : 'KML or GPX file'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.folder_open), + onPressed: () => _pickRouteFile(context, appState), + tooltip: 'Load route file', ), - TextButton.icon( - icon: const Icon(Icons.delete_sweep, size: 18), - label: const Text('Delete All'), - onPressed: () => _confirmDeleteAllLogs(context, appState), + if (appState.hasSimulatorRoute) + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + appState.clearSimulatorRoute(); + AppToast.info(context, 'Route cleared'); + }, + tooltip: 'Clear route', + ), + ], + ), + ), + ListTile( + leading: const SizedBox(width: 24), + title: const Text('Reset Position'), + subtitle: Text(appState.hasSimulatorRoute + ? 'Reset to route start' + : 'Reset to Ottawa downtown'), + trailing: IconButton( + icon: const Icon(Icons.restart_alt), + onPressed: () { + appState.resetGpsSimulator(); + AppToast.info( + context, + appState.hasSimulatorRoute + ? 'Reset to route start' + : 'GPS simulator reset to Ottawa downtown', + ); + }, + ), + ), + ], + ]), + + // Debug section (always visible on mobile) + if (!kIsWeb) + _buildSection(context, 'Debug', [ + SwitchListTile( + secondary: Icon( + Icons.bug_report, + color: appState.debugLogsEnabled ? Colors.orange : null, + ), + title: Row( + children: [ + const Text('Debug Logs'), + if (appState.debugLogsEnabled) ...[ + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: Colors.orange, + borderRadius: BorderRadius.circular(4), + ), + child: const Text( + 'LOGGING', + style: TextStyle( + fontSize: 9, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), ), ], ], ), - ), - - // Log files list or empty message - if (appState.debugLogFiles.isEmpty) - Padding( - padding: const EdgeInsets.all(16), - child: Text( - 'No debug logs yet', - style: TextStyle(color: Colors.grey.shade500, fontSize: 13), - ), - ) - else - ...appState.debugLogFiles.asMap().entries.map((entry) { - final index = entry.key; - final file = entry.value; - final filename = file.path.split('/').last; - final sizeBytes = file.lengthSync(); - final isCurrentLog = index == 0; - final timestampMatch = RegExp(r'meshmapper-debug-(\d+)\.txt').firstMatch(filename); - final fileDate = timestampMatch != null - ? DateTime.fromMillisecondsSinceEpoch(int.parse(timestampMatch.group(1)!) * 1000) - : null; - final dateStr = fileDate != null ? DateFormat('MMM d, h:mm a').format(fileDate) : filename; - - String sizeDisplay; - final partCount = DebugFileLogger.estimatePartCount(sizeBytes); - if (sizeBytes >= DebugFileLogger.maxUploadSizeBytes) { - final sizeMb = (sizeBytes / 1024 / 1024).toStringAsFixed(1); - sizeDisplay = '$sizeMb MB ($partCount parts)'; + subtitle: Text( + appState.debugLogsEnabled + ? 'Writing logs to file' + : 'Enable to save debug logs to device', + ), + value: appState.debugLogsEnabled, + onChanged: (value) async { + if (value) { + await appState.enableDebugLogs(); } else { - sizeDisplay = '${(sizeBytes / 1024).toStringAsFixed(1)} KB'; - } - if (isCurrentLog) { - sizeDisplay = '$sizeDisplay (current)'; + await appState.disableDebugLogs(); } - - return ListTile( - leading: const Icon(Icons.description, size: 20), - title: Text(dateStr, style: const TextStyle(fontSize: 13)), - subtitle: Text( - sizeDisplay, - style: const TextStyle(fontSize: 11), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.visibility, size: 20), - onPressed: () => _showLogViewer(context, appState, file), - tooltip: 'View', + }, + ), + if (appState.debugLogsEnabled || appState.debugLogFiles.isNotEmpty) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 4), + child: Row( + children: [ + Text( + 'Log Files', + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Colors.grey.shade600, + ), + ), + const Spacer(), + if (appState.debugLogFiles.isNotEmpty) ...[ + TextButton.icon( + icon: const Icon(Icons.cloud_upload, size: 18), + label: const Text('Upload'), + onPressed: () => _showUploadLogsDialog(context, appState), ), - IconButton( - icon: const Icon(Icons.share, size: 20), - onPressed: () => appState.shareDebugLog(file), - tooltip: 'Share', + TextButton.icon( + icon: const Icon(Icons.delete_sweep, size: 18), + label: const Text('Delete All'), + onPressed: () => _confirmDeleteAllLogs(context, appState), ), ], + ], + ), + ), + if (appState.debugLogFiles.isEmpty) + Padding( + padding: const EdgeInsets.all(16), + child: Text( + 'No debug logs yet', + style: TextStyle(color: Colors.grey.shade500, fontSize: 13), ), - ); - }), - ], - ], + ) + else + ...appState.debugLogFiles.asMap().entries.map((entry) { + final index = entry.key; + final file = entry.value; + final filename = file.path.split('/').last; + final sizeBytes = file.lengthSync(); + final isCurrentLog = index == 0; + final timestampMatch = RegExp(r'meshmapper-debug-(\d+)\.txt').firstMatch(filename); + final fileDate = timestampMatch != null + ? DateTime.fromMillisecondsSinceEpoch(int.parse(timestampMatch.group(1)!) * 1000) + : null; + final dateStr = fileDate != null ? DateFormat('MMM d, h:mm a').format(fileDate) : filename; + + String sizeDisplay; + final partCount = DebugFileLogger.estimatePartCount(sizeBytes); + if (sizeBytes >= DebugFileLogger.maxUploadSizeBytes) { + final sizeMb = (sizeBytes / 1024 / 1024).toStringAsFixed(1); + sizeDisplay = '$sizeMb MB ($partCount parts)'; + } else { + sizeDisplay = '${(sizeBytes / 1024).toStringAsFixed(1)} KB'; + } + if (isCurrentLog) { + sizeDisplay = '$sizeDisplay (current)'; + } - const SizedBox(height: 32), + return ListTile( + leading: const Icon(Icons.description, size: 20), + title: Text(dateStr, style: const TextStyle(fontSize: 13)), + subtitle: Text( + sizeDisplay, + style: const TextStyle(fontSize: 11), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.visibility, size: 20), + onPressed: () => _showLogViewer(context, appState, file), + tooltip: 'View', + ), + IconButton( + icon: const Icon(Icons.share, size: 20), + onPressed: () => appState.shareDebugLog(file), + tooltip: 'Share', + ), + ], + ), + ); + }), + ], + ]), ], ), ); } - Widget _buildSectionHeader(BuildContext context, String title) { + Widget _buildSection(BuildContext context, String title, List children) { return Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), - child: Text( - title, - style: Theme.of(context).textTheme.titleSmall?.copyWith( - color: Theme.of(context).colorScheme.primary, - fontWeight: FontWeight.bold, + padding: const EdgeInsets.only(bottom: 8), + child: Card( + margin: EdgeInsets.zero, + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), + child: Text( + title, + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + ), + ), ), + ...children, + const SizedBox(height: 4), + ], + ), ), ); } @@ -1179,6 +1148,45 @@ class _SettingsScreenState extends State { ); } + void _showDeleteChannelInfo(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.delete_sweep, size: 24), + SizedBox(width: 8), + Flexible(child: Text('Delete Channel on Disconnect')), + ], + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'When enabled, the #wardriving channel is removed from your radio when you disconnect. ' + 'This keeps your radio\'s channel list clean.\n\n' + 'When disabled, the channel remains on the radio after disconnect.', + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 12), + Text( + 'If the app crashes or BLE disconnects unexpectedly, your device ' + 'may retain the #wardriving channel until you reconnect and properly disconnect.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Got it'), + ), + ], + ), + ); + } + void _showHopBytesInfo(BuildContext context) { showDialog( context: context, @@ -1907,29 +1915,7 @@ class _BackgroundModeToggleState extends State<_BackgroundModeToggle> Icons.location_on, color: _hasAlwaysPermission ? Colors.green : null, ), - title: Row( - children: [ - const Text('Background Location'), - if (_hasAlwaysPermission) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.green, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'ALWAYS', - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ], - ], - ), + title: const Text('Background Location'), subtitle: Text( _hasAlwaysPermission ? 'Location tracking works in background' From 914b6883c34865fc0fa8f8186beabb5f78493298 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 08:44:38 -0400 Subject: [PATCH 50/57] **New Features** - Live repeater snapshot: enable it in Settings to see the top 3 responded repeaters from your last ping, updating live as you wardrive **Improvements** - Redesigned the Log tab - Redesigned the Settings tab --- lib/models/user_preferences.dart | 12 ++++- lib/providers/app_state_provider.dart | 70 +++++++++++++++++++++++++++ lib/screens/settings_screen.dart | 9 ++++ lib/widgets/map_widget.dart | 68 +++++++++++++++++++++++++- 4 files changed, 156 insertions(+), 3 deletions(-) diff --git a/lib/models/user_preferences.dart b/lib/models/user_preferences.dart index 331519b..4063fc8 100644 --- a/lib/models/user_preferences.dart +++ b/lib/models/user_preferences.dart @@ -82,6 +82,9 @@ class UserPreferences { /// Auto-stop auto-ping after 30 minutes of idle (no movement) final bool autoStopAfterIdle; + /// Show top 3 repeaters by SNR on the map during wardriving + final bool showTopRepeaters; + const UserPreferences({ this.powerLevel = 0.3, this.txPower = 22, @@ -110,6 +113,7 @@ class UserPreferences { this.deleteChannelOnDisconnect = true, this.minPingDistanceMeters = 25, this.autoStopAfterIdle = true, + this.showTopRepeaters = false, }); /// Create from JSON (for persistence) @@ -142,6 +146,7 @@ class UserPreferences { deleteChannelOnDisconnect: (json['deleteChannelOnDisconnect'] as bool?) ?? true, minPingDistanceMeters: (json['minPingDistanceMeters'] as int?) ?? 25, autoStopAfterIdle: (json['autoStopAfterIdle'] as bool?) ?? true, + showTopRepeaters: (json['showTopRepeaters'] as bool?) ?? false, ); } @@ -175,6 +180,7 @@ class UserPreferences { 'deleteChannelOnDisconnect': deleteChannelOnDisconnect, 'minPingDistanceMeters': minPingDistanceMeters, 'autoStopAfterIdle': autoStopAfterIdle, + 'showTopRepeaters': showTopRepeaters, }; } @@ -207,6 +213,7 @@ class UserPreferences { bool? deleteChannelOnDisconnect, int? minPingDistanceMeters, bool? autoStopAfterIdle, + bool? showTopRepeaters, }) { return UserPreferences( powerLevel: powerLevel ?? this.powerLevel, @@ -236,6 +243,7 @@ class UserPreferences { deleteChannelOnDisconnect: deleteChannelOnDisconnect ?? this.deleteChannelOnDisconnect, minPingDistanceMeters: minPingDistanceMeters ?? this.minPingDistanceMeters, autoStopAfterIdle: autoStopAfterIdle ?? this.autoStopAfterIdle, + showTopRepeaters: showTopRepeaters ?? this.showTopRepeaters, ); } @@ -293,7 +301,8 @@ class UserPreferences { other.discDropEnabled == discDropEnabled && other.deleteChannelOnDisconnect == deleteChannelOnDisconnect && other.minPingDistanceMeters == minPingDistanceMeters && - other.autoStopAfterIdle == autoStopAfterIdle; + other.autoStopAfterIdle == autoStopAfterIdle && + other.showTopRepeaters == showTopRepeaters; } @override @@ -325,6 +334,7 @@ class UserPreferences { deleteChannelOnDisconnect, minPingDistanceMeters, autoStopAfterIdle, + showTopRepeaters, ]); } diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index b152b1b..a223b68 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -165,6 +165,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { final List _discLogEntries = []; final List _traceLogEntries = []; + // Top repeaters overlay — updated live on each ping event + List<({String repeaterId, double snr})> _topRepeatersOverlay = []; + // Targeted mode state String? _targetRepeaterId; @@ -337,6 +340,38 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool get isScanning => _isScanning; List get txPings => List.unmodifiable(_txPings); List get rxPings => List.unmodifiable(_rxPings); + + /// Top 3 repeaters by best SNR (1-byte IDs only) across TX echoes and RX observations + List<({String repeaterId, double snr})> get topRepeatersBySnr => _topRepeatersOverlay; + + /// Update the top repeaters overlay with results from the latest ping. + /// New repeaters from this ping take priority (sorted by best SNR first). + /// Remaining slots are filled with carryover from the previous display. + void _updateTopRepeaters(List<({String repeaterId, double snr})> current) { + // Deduplicate current entries, keeping best SNR per repeater + final bestSnr = {}; + for (final r in current) { + final key = r.repeaterId.toUpperCase(); + if (!bestSnr.containsKey(key) || r.snr > bestSnr[key]!) { + bestSnr[key] = r.snr; + } + } + final fresh = bestSnr.entries + .map((e) => (repeaterId: e.key, snr: e.value)) + .toList() + ..sort((a, b) => b.snr.compareTo(a.snr)); + + if (fresh.length >= 3) { + _topRepeatersOverlay = fresh.take(3).toList(); + } else { + // Fill remaining slots with previous entries not already in fresh + final freshIds = fresh.map((r) => r.repeaterId).toSet(); + final carryover = _topRepeatersOverlay + .where((r) => !freshIds.contains(r.repeaterId)) + .toList(); + _topRepeatersOverlay = [...fresh, ...carryover].take(3).toList(); + } + } List get txLogEntries => List.unmodifiable(_txLogEntries); List get rxLogEntries => List.unmodifiable(_rxLogEntries); List get discLogEntries => List.unmodifiable(_discLogEntries); @@ -1281,6 +1316,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { )); if (_rxLogEntries.length > _maxLogEntries) _rxLogEntries.removeAt(0); + // Update top repeaters overlay with this RX observation + if (ping.repeaterId.length == 2) { + _updateTopRepeaters([(repeaterId: ping.repeaterId.toUpperCase(), snr: ping.snr)]); + } + notifyListeners(); }; @@ -1351,6 +1391,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ); _txLogEntries[_txLogEntries.length - 1] = updatedEntry; debugLog('[APP] Updated TxLogEntry with ${existingEvents.length} events (real-time)'); + + // Update top repeaters overlay with current TX echoes + _updateTopRepeaters(existingEvents + .where((e) => e.repeaterId.length == 2 && e.snr != null) + .map((e) => (repeaterId: e.repeaterId.toUpperCase(), snr: e.snr!)) + .toList()); + debugLog('[APP] Calling notifyListeners() to update UI'); notifyListeners(); debugLog('[APP] notifyListeners() completed'); @@ -1395,6 +1442,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (isNew) { _audioService.playReceiveSound(); } + + // Update top repeaters overlay with all discovered nodes from this ping + _updateTopRepeaters(discPing.discoveredNodes + .where((n) => n.repeaterId.length == 2) + .map((n) => (repeaterId: n.repeaterId.toUpperCase(), snr: n.localSnr)) + .toList()); + notifyListeners(); }; @@ -1724,6 +1778,10 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Created IMMEDIATE RX pin for repeater: ${observation.repeaterId} ' 'at ${observation.lat.toStringAsFixed(5)},${observation.lon.toStringAsFixed(5)} ' '(batch tracking: ${_currentBatchRepeaters.length} repeaters, rxCount: ${_pingStats.rxCount})'); + // Update top repeaters overlay immediately + if (observation.repeaterId.length == 2 && observation.snr != null) { + _updateTopRepeaters([(repeaterId: repeaterKey, snr: observation.snr!)]); + } // Play receive sound for new RX observation _audioService.playReceiveSound(); // Record RX event for noise floor graph with location and repeater info @@ -1829,6 +1887,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Added RX log entry: repeater=${entry.repeaterId}, ' 'snr=${entry.snr ?? 'null'}, pathLen=${entry.pathLength}'); + // Update top repeaters overlay with this RX observation + if (entry.repeaterId.length == 2 && entry.snr != null) { + _updateTopRepeaters([(repeaterId: entry.repeaterId.toUpperCase(), snr: entry.snr!)]); + } + // Note: RX count is incremented in onObservation when pin is created (immediate feedback) // Enqueue to API with formatted heard_repeats string @@ -2715,6 +2778,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _discLogEntries.clear(); _traceLogEntries.clear(); _errorLogEntries.clear(); + _topRepeatersOverlay = []; notifyListeners(); } @@ -2735,6 +2799,12 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _traceLogEntries.removeLast(); } debugLog('[APP] Trace log entry added: target=${entry.targetRepeaterId}, success=${entry.success}'); + + // Update top repeaters overlay with successful trace result + if (entry.success && entry.targetRepeaterId.length == 2 && entry.localSnr != null) { + _updateTopRepeaters([(repeaterId: entry.targetRepeaterId.toUpperCase(), snr: entry.localSnr!)]); + } + notifyListeners(); } diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 9c26a4a..62817d3 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -157,6 +157,15 @@ class _SettingsScreenState extends State { appState.setUnitSystem(isImperial ? 'imperial' : 'metric'); }, ), + SwitchListTile( + secondary: const Icon(Icons.cell_tower), + title: const Text('Top Repeaters on Map'), + subtitle: const Text('Show top 3 repeaters by SNR while wardriving'), + value: prefs.showTopRepeaters, + onChanged: (value) { + appState.updatePreferences(prefs.copyWith(showTopRepeaters: value)); + }, + ), if (!kIsWeb) _BackgroundModeToggle(appState: appState), ]), diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 55244f9..527b8fd 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -569,11 +569,20 @@ class _MapWidgetState extends State with TickerProviderStateMixin { // Map _buildMap(appState, center), - // GPS Info overlay (top-left, respects dynamic island in landscape) + // GPS Info + Top Repeaters overlay (top-left, respects dynamic island in landscape) Positioned( top: topPadding, left: leftPadding, - child: _buildGpsInfoOverlay(appState), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildGpsInfoOverlay(appState), + if (appState.preferences.showTopRepeaters && appState.autoPingEnabled) ...[ + const SizedBox(height: 6), + _buildTopRepeatersOverlay(appState), + ], + ], + ), ), // Map controls - top-right in both orientations, collapsible @@ -721,6 +730,61 @@ class _MapWidgetState extends State with TickerProviderStateMixin { } /// GPS info overlay (top-left corner) + /// Top 3 repeaters by SNR overlay (bottom-right of map) + Widget _buildTopRepeatersOverlay(AppStateProvider appState) { + final topRepeaters = appState.topRepeatersBySnr; + if (topRepeaters.isEmpty) return const SizedBox.shrink(); + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.7), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (final r in topRepeaters) + Padding( + padding: const EdgeInsets.symmetric(vertical: 1), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + r.repeaterId, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: Colors.white, + ), + ), + const SizedBox(width: 6), + Text( + '${r.snr.toStringAsFixed(1)} dB', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: _snrColor(r.snr), + ), + ), + ], + ), + ), + ], + ), + ); + } + + /// SNR color: green > 5, orange -1..5, red <= -1 + static Color _snrColor(double snr) { + if (snr <= -1) return Colors.red; + if (snr <= 5) return Colors.orange; + return Colors.green; + } + Widget _buildGpsInfoOverlay(AppStateProvider appState) { final position = appState.currentPosition; final hasGps = position != null; From 0a5ad3185642bf8a62f01e8b101b88453cba2fd5 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 08:50:20 -0400 Subject: [PATCH 51/57] ### Bug Fixes - Connection screen now shows a "Server Unreachable" message with offline mode suggestion when auth fails due to network errors, instead of a generic error. - Fixed zone check flooding when driving with no network. Previously, every GPS update triggered an API call when the network was down. Position is now tracked even on failed calls, so retries are handled by the 5-second timer instead. ### Improvements - Online/offline toggle redesigned to look more clearly like a button. --- lib/providers/app_state_provider.dart | 9 +++++++++ lib/screens/connection_screen.dart | 12 ++++++++---- lib/widgets/offline_mode_toggle.dart | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index a223b68..daa4a29 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -102,6 +102,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ConnectionStep _connectionStep = ConnectionStep.disconnected; String? _connectionError; bool _isAuthError = false; // Track if connection failed due to auth + bool _isNetworkError = false; // Track if connection failed due to network // Bluetooth adapter state (on/off) BluetoothAdapterState _bluetoothAdapterState = BluetoothAdapterState.unknown; @@ -310,6 +311,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { ConnectionStep get connectionStep => _connectionStep; String? get connectionError => _connectionError; bool get isAuthError => _isAuthError; + bool get isNetworkError => _isNetworkError; BluetoothAdapterState get bluetoothAdapterState => _bluetoothAdapterState; bool get isBluetoothOn => _bluetoothAdapterState == BluetoothAdapterState.on; bool get isBluetoothOff => _bluetoothAdapterState == BluetoothAdapterState.off; @@ -821,6 +823,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _discoveredDevices = []; _connectionError = null; _isAuthError = false; + _isNetworkError = false; notifyListeners(); // Listen for discovered devices using subscription so stopScan() can cancel @@ -888,6 +891,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { try { _connectionError = null; _isAuthError = false; + _isNetworkError = false; // Clean up any previous connection first if (_meshCoreConnection != null) { @@ -1703,12 +1707,14 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { final errorParts = parts[1].split(':'); final reason = errorParts.isNotEmpty ? errorParts[0] : 'unknown'; final serverMessage = errorParts.length > 1 ? errorParts.sublist(1).join(':') : null; + _isNetworkError = reason == 'network_error'; _connectionError = _getErrorMessage(reason, serverMessage); } else { _connectionError = 'Authentication failed'; } } else { _isAuthError = false; + _isNetworkError = false; // Provide clean user-facing messages for common BLE errors if (errorStr.contains('timeout') || errorStr.contains('Timeout') || errorStr.contains('timed out')) { _connectionError = 'Bluetooth connection scan timed out'; @@ -3974,6 +3980,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[GEOFENCE] API response received: ${result != null ? 'valid' : 'null'}'); if (result == null) { + // Update position even on failure to prevent zone check flooding + // (without this, every GPS update re-triggers a zone check while driving) + _lastZoneCheckPosition = _currentPosition; debugError('[GEOFENCE] Zone status check failed: no response from API'); _scheduleZoneCheckRetry( seconds: 5, diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index d8134f9..9f3bb88 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -1002,18 +1002,22 @@ class _ConnectionScreenState extends State with WidgetsBinding mainAxisSize: MainAxisSize.min, children: [ Icon( - Icons.error_outline, + appState.isNetworkError ? Icons.cloud_off : Icons.error_outline, size: isLandscape ? 48 : 64, - color: Colors.red, + color: appState.isNetworkError ? Colors.orange : Colors.red, ), SizedBox(height: isLandscape ? 8 : 16), Text( - appState.isAuthError ? 'Authentication Failed' : 'Connection Failed', + appState.isNetworkError + ? 'Server Unreachable' + : appState.isAuthError ? 'Authentication Failed' : 'Connection Failed', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text( - appState.connectionError ?? 'Unknown error', + appState.isNetworkError + ? 'MeshMapper services unreachable, try again or use offline mode.' + : appState.connectionError ?? 'Unknown error', textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodySmall, ), diff --git a/lib/widgets/offline_mode_toggle.dart b/lib/widgets/offline_mode_toggle.dart index cfdb9cb..b54aec5 100644 --- a/lib/widgets/offline_mode_toggle.dart +++ b/lib/widgets/offline_mode_toggle.dart @@ -167,7 +167,7 @@ class OfflineModeToggle extends StatelessWidget { ), const SizedBox(width: 8), Text( - offlineMode ? 'Offline' : 'Online', + offlineMode ? 'Go Online' : 'Go Offline', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, From 7735ef57047d20fcfbc17b85cf3d06234227f6d9 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 09:05:06 -0400 Subject: [PATCH 52/57] - Updated landscape controls to match the new portrait layout and added Trace mode support. - Updated the UI for the top heard repeaters display. --- lib/providers/app_state_provider.dart | 19 ++-- lib/screens/settings_screen.dart | 2 +- lib/widgets/map_widget.dart | 88 ++++++++++------ lib/widgets/ping_controls.dart | 140 +++++--------------------- 4 files changed, 96 insertions(+), 153 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index daa4a29..28d93d4 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -1321,9 +1321,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { if (_rxLogEntries.length > _maxLogEntries) _rxLogEntries.removeAt(0); // Update top repeaters overlay with this RX observation - if (ping.repeaterId.length == 2) { - _updateTopRepeaters([(repeaterId: ping.repeaterId.toUpperCase(), snr: ping.snr)]); - } + _updateTopRepeaters([(repeaterId: ping.repeaterId.toUpperCase(), snr: ping.snr)]); notifyListeners(); }; @@ -1398,7 +1396,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update top repeaters overlay with current TX echoes _updateTopRepeaters(existingEvents - .where((e) => e.repeaterId.length == 2 && e.snr != null) + .where((e) => e.snr != null) .map((e) => (repeaterId: e.repeaterId.toUpperCase(), snr: e.snr!)) .toList()); @@ -1449,7 +1447,6 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update top repeaters overlay with all discovered nodes from this ping _updateTopRepeaters(discPing.discoveredNodes - .where((n) => n.repeaterId.length == 2) .map((n) => (repeaterId: n.repeaterId.toUpperCase(), snr: n.localSnr)) .toList()); @@ -1785,7 +1782,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { 'at ${observation.lat.toStringAsFixed(5)},${observation.lon.toStringAsFixed(5)} ' '(batch tracking: ${_currentBatchRepeaters.length} repeaters, rxCount: ${_pingStats.rxCount})'); // Update top repeaters overlay immediately - if (observation.repeaterId.length == 2 && observation.snr != null) { + if (observation.snr != null) { _updateTopRepeaters([(repeaterId: repeaterKey, snr: observation.snr!)]); } // Play receive sound for new RX observation @@ -1894,7 +1891,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { 'snr=${entry.snr ?? 'null'}, pathLen=${entry.pathLength}'); // Update top repeaters overlay with this RX observation - if (entry.repeaterId.length == 2 && entry.snr != null) { + if (entry.snr != null) { _updateTopRepeaters([(repeaterId: entry.repeaterId.toUpperCase(), snr: entry.snr!)]); } @@ -2784,7 +2781,6 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _discLogEntries.clear(); _traceLogEntries.clear(); _errorLogEntries.clear(); - _topRepeatersOverlay = []; notifyListeners(); } @@ -2807,8 +2803,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Trace log entry added: target=${entry.targetRepeaterId}, success=${entry.success}'); // Update top repeaters overlay with successful trace result - if (entry.success && entry.targetRepeaterId.length == 2 && entry.localSnr != null) { - _updateTopRepeaters([(repeaterId: entry.targetRepeaterId.toUpperCase(), snr: entry.localSnr!)]); + if (entry.success && entry.localSnr != null) { + // Truncate 4-byte trace IDs to 3 bytes (6 hex chars) to fit overlay + final id = entry.targetRepeaterId.toUpperCase(); + final displayId = id.length > 6 ? id.substring(0, 6) : id; + _updateTopRepeaters([(repeaterId: displayId, snr: entry.localSnr!)]); } notifyListeners(); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 62817d3..e0d144f 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -160,7 +160,7 @@ class _SettingsScreenState extends State { SwitchListTile( secondary: const Icon(Icons.cell_tower), title: const Text('Top Repeaters on Map'), - subtitle: const Text('Show top 3 repeaters by SNR while wardriving'), + subtitle: const Text('Show top 3 repeaters by SNR from last ping'), value: prefs.showTopRepeaters, onChanged: (value) { appState.updatePreferences(prefs.copyWith(showTopRepeaters: value)); diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 527b8fd..9a1617a 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -577,7 +577,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildGpsInfoOverlay(appState), - if (appState.preferences.showTopRepeaters && appState.autoPingEnabled) ...[ + if (appState.preferences.showTopRepeaters) ...[ const SizedBox(height: 6), _buildTopRepeatersOverlay(appState), ], @@ -733,7 +733,6 @@ class _MapWidgetState extends State with TickerProviderStateMixin { /// Top 3 repeaters by SNR overlay (bottom-right of map) Widget _buildTopRepeatersOverlay(AppStateProvider appState) { final topRepeaters = appState.topRepeatersBySnr; - if (topRepeaters.isEmpty) return const SizedBox.shrink(); return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), @@ -745,34 +744,67 @@ class _MapWidgetState extends State with TickerProviderStateMixin { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - for (final r in topRepeaters) - Padding( - padding: const EdgeInsets.symmetric(vertical: 1), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - r.repeaterId, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: Colors.white, - ), - ), - const SizedBox(width: 6), - Text( - '${r.snr.toStringAsFixed(1)} dB', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: _snrColor(r.snr), - ), - ), - ], + const Text( + 'Top Heard', + style: TextStyle( + fontSize: 9, + fontWeight: FontWeight.w500, + color: Colors.white54, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 2), + if (topRepeaters.isEmpty) + const Text( + '---', + style: TextStyle( + fontSize: 11, + fontFamily: 'monospace', + color: Colors.white38, ), ), + if (topRepeaters.isNotEmpty) + Table( + defaultColumnWidth: const IntrinsicColumnWidth(), + columnWidths: const { + 0: IntrinsicColumnWidth(), + 1: FixedColumnWidth(8), + 2: IntrinsicColumnWidth(), + }, + children: [ + for (final r in topRepeaters) + TableRow( + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 1), + child: Text( + r.repeaterId, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: Colors.white, + ), + ), + ), + const SizedBox(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 1), + child: Text( + r.snr.toStringAsFixed(1), + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: _snrColor(r.snr), + ), + ), + ), + ], + ), + ], + ), ], ), ); diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index d1e6695..5c4f2e6 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -5,7 +5,6 @@ import 'package:provider/provider.dart'; import '../providers/app_state_provider.dart'; import '../services/ping_service.dart'; import '../utils/debug_logger_io.dart'; -import 'offline_mode_toggle.dart'; import 'repeater_picker_sheet.dart'; /// Modern ping control panel with icon-based buttons and animated status @@ -450,11 +449,13 @@ class _TargetedPingSection extends StatefulWidget { final bool isAnyModeRunning; final bool cooldownActive; final int cooldownRemaining; + final bool compact; const _TargetedPingSection({ required this.isAnyModeRunning, required this.cooldownActive, required this.cooldownRemaining, + this.compact = false, }); @override @@ -578,24 +579,26 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { size: 18, color: effectiveColor, ), - const SizedBox(width: 8), - Expanded( - child: Text( - _isStarting - ? 'Starting...' - : isTargetedRunning - ? (statusText ?? 'Stop') - : widget.cooldownActive - ? 'Cooldown ${widget.cooldownRemaining}s' - : 'Trace Mode', - style: TextStyle( - fontSize: 13, - fontWeight: isTargetedRunning ? FontWeight.w600 : FontWeight.w500, - color: isEnabled ? colorScheme.onSurface : colorScheme.onSurfaceVariant.withValues(alpha: 0.5), + if (!widget.compact) ...[ + const SizedBox(width: 8), + Expanded( + child: Text( + _isStarting + ? 'Starting...' + : isTargetedRunning + ? (statusText ?? 'Stop') + : widget.cooldownActive + ? 'Cooldown ${widget.cooldownRemaining}s' + : 'Trace Mode', + style: TextStyle( + fontSize: 13, + fontWeight: isTargetedRunning ? FontWeight.w600 : FontWeight.w500, + color: isEnabled ? colorScheme.onSurface : colorScheme.onSurfaceVariant.withValues(alpha: 0.5), + ), + overflow: TextOverflow.ellipsis, ), - overflow: TextOverflow.ellipsis, ), - ), + ], ], ), ), @@ -1148,11 +1151,6 @@ class LandscapePingControls extends StatelessWidget { final prefs = appState.preferences; final isPowerSet = prefs.autoPowerSet || prefs.powerLevelSet || appState.deviceModel != null; - // Antenna selector - final soundEnabled = appState.isSoundEnabled; - final offlineMode = appState.offlineMode; - final isConnected = appState.isConnected; - return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -1248,34 +1246,12 @@ class LandscapePingControls extends StatelessWidget { ), const SizedBox(height: 10), - // Compact row for toggles - Row( - children: [ - Expanded( - child: _LandscapeToggle( - icon: offlineMode ? Icons.cloud_off : Icons.cloud_queue, - label: 'Offline', - isOn: offlineMode, - color: Colors.orange, - onTap: () => OfflineModeToggle.handleOfflineModeToggle( - context, - appState, - offlineMode, - isConnected, - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: _LandscapeToggle( - icon: soundEnabled ? Icons.volume_up : Icons.volume_off, - label: 'Sound', - isOn: soundEnabled, - color: Colors.blue, - onTap: () => appState.toggleSoundEnabled(), - ), - ), - ], + // Targeted Ping controls (Trace Mode) + _TargetedPingSection( + isAnyModeRunning: isActiveModeRunning || isPassiveModeRunning || isHybridModeRunning, + cooldownActive: cooldownActive, + cooldownRemaining: cooldownRemaining, + compact: true, ), ], ); @@ -1574,70 +1550,6 @@ class _LandscapeIconButtonState extends State<_LandscapeIconButton> } /// Compact toggle button for landscape panel -class _LandscapeToggle extends StatelessWidget { - final IconData icon; - final String label; - final bool isOn; - final Color color; - final VoidCallback onTap; - - const _LandscapeToggle({ - required this.icon, - required this.label, - required this.isOn, - required this.color, - required this.onTap, - }); - - @override - Widget build(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; - final activeColor = isOn ? color : colorScheme.onSurfaceVariant; - - return Material( - color: Colors.transparent, - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(10), - child: Container( - height: 38, - padding: const EdgeInsets.symmetric(horizontal: 10), - decoration: BoxDecoration( - color: isOn - ? activeColor.withValues(alpha: 0.12) - : colorScheme.onSurface.withValues(alpha: 0.04), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: isOn - ? activeColor.withValues(alpha: 0.35) - : colorScheme.outline.withValues(alpha: 0.15), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - icon, - size: 16, - color: isOn ? activeColor : colorScheme.onSurfaceVariant, - ), - const SizedBox(width: 6), - Text( - label, - style: TextStyle( - fontSize: 12, - fontWeight: isOn ? FontWeight.w600 : FontWeight.w500, - color: isOn ? activeColor : colorScheme.onSurfaceVariant, - ), - ), - ], - ), - ), - ), - ); - } -} - /// Compact action button for minimized panel - horizontal pill layout /// Supports expanding to show label when active class _CompactActionButton extends StatefulWidget { From 23c58499f7657a0fe17b7638a546c0d126eba73a Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 09:13:36 -0400 Subject: [PATCH 53/57] - Added text scale clamping for device accessibility settings. Previously the system text scale factor was applied unclamped across the entire app, which could break layouts at larger text sizes. --- lib/main.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 49efe51..08ef6ef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -247,6 +247,14 @@ class _ThemedAppState extends State<_ThemedApp> { return MaterialApp( title: 'MeshMapper', + builder: (context, child) { + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaler: TextScaler.noScaling, + ), + child: child!, + ); + }, theme: ThemeData( colorScheme: lightColorScheme, scaffoldBackgroundColor: const Color(0xFFF1F5F9), // slate-100 From 6cc9d413c75893578146b42f9bbacc7053a9ac22 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 21:39:43 -0400 Subject: [PATCH 54/57] Fixing some font sizing and layouts --- lib/providers/app_state_provider.dart | 96 ++++++++--- lib/screens/log_screen.dart | 37 +++-- lib/screens/settings_screen.dart | 191 +++++++++++++++++----- lib/services/api_service.dart | 223 +++++++++++++++++++------- 4 files changed, 414 insertions(+), 133 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 28d93d4..2f98a53 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -64,6 +64,8 @@ enum OfflineUploadResult { authFailed, /// Some pings failed to upload partialFailure, + /// Another upload is already in progress + uploadInProgress, } /// Main application state provider @@ -484,6 +486,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Offline mode bool get offlineMode => _preferences.offlineMode; List get offlineSessions => _offlineSessionService.sessions; + bool _isUploadingOfflineSession = false; + bool get isUploadingOfflineSession => _isUploadingOfflineSession; // Developer mode bool get developerModeEnabled => _preferences.developerModeEnabled; @@ -3319,14 +3323,42 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } /// Upload an offline session with authenticated API session - /// Uses stored device credentials to authenticate before uploading + /// Uses stored device credentials to authenticate before uploading. + /// Session is fully isolated from the shared ApiService state — offline uploads + /// never touch _sessionId and cannot trigger BLE disconnect on failure. /// + /// @param onProgress Optional callback for progress updates (e.g., "Batch 1/3") /// Returns the result of the upload operation - Future uploadOfflineSessionWithAuth(String filename) async { + Future uploadOfflineSessionWithAuth( + String filename, { + void Function(String status)? onProgress, + }) async { + // Concurrency guard — only one offline upload at a time + if (_isUploadingOfflineSession) { + debugWarn('[OFFLINE] Upload already in progress, rejecting concurrent request'); + return OfflineUploadResult.uploadInProgress; + } + + _isUploadingOfflineSession = true; + notifyListeners(); + + try { + return await _uploadOfflineSessionIsolated(filename, onProgress: onProgress); + } finally { + _isUploadingOfflineSession = false; + notifyListeners(); + } + } + + /// Internal implementation of offline session upload with isolated session + Future _uploadOfflineSessionIsolated( + String filename, { + void Function(String status)? onProgress, + }) async { // 1. Get session with stored device credentials final session = _offlineSessionService.getSession(filename); if (session == null) { - debugLog('[APP] Offline session not found: $filename'); + debugLog('[OFFLINE] Session not found: $filename'); return OfflineUploadResult.notFound; } @@ -3337,25 +3369,28 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { .toList(); if (pings == null || pings.isEmpty) { - debugLog('[APP] Offline session has no pings: $filename'); + debugLog('[OFFLINE] Session has no pings: $filename'); return OfflineUploadResult.invalidSession; } // 2. Get device credentials from session final publicKey = session.devicePublicKey; if (publicKey == null) { - debugLog('[APP] Offline session missing device public key: $filename'); + debugLog('[OFFLINE] Session missing device public key: $filename'); return OfflineUploadResult.invalidSession; } final deviceName = session.deviceName; if (deviceName == null || deviceName.isEmpty) { - debugLog('[APP] Offline session missing device name: $filename'); + debugLog('[OFFLINE] Session missing device name: $filename'); return OfflineUploadResult.invalidSession; } - // 3. Authenticate with offline_mode: true - debugLog('[APP] Authenticating for offline upload with device: $deviceName'); + onProgress?.call('Authenticating...'); + + // 3. Authenticate with offline_mode: true, skipSessionStore: true + // This prevents writing to shared _sessionId/_txAllowed/etc. + debugLog('[OFFLINE] Authenticating for offline upload with device: $deviceName'); final authResult = await _apiService.requestAuth( reason: 'connect', publicKey: publicKey, @@ -3368,22 +3403,23 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { lon: _currentPosition?.longitude, accuracyMeters: _currentPosition?.accuracy, offlineMode: true, + skipSessionStore: true, ); Map? effectiveAuth = authResult; if (authResult == null) { - debugError('[API] Offline upload auth failed: network error'); + debugError('[OFFLINE] Auth failed: network error'); return OfflineUploadResult.authFailed; } if (authResult['success'] != true) { final reason = authResult['reason'] as String? ?? 'unknown'; - debugLog('[API] Offline upload Stage 1 failed: $reason'); + debugLog('[OFFLINE] Stage 1 failed: $reason'); // Stage 2: If unknown_device and we have a stored contactUri, attempt registration if (reason == 'unknown_device' && session.contactUri != null) { - debugLog('[APP] Stage 2: Attempting registration via stored contact URI...'); + debugLog('[OFFLINE] Stage 2: Attempting registration via stored contact URI...'); final registerResult = await _apiService.requestAuth( reason: 'register', contactUri: session.contactUri, @@ -3396,62 +3432,76 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { lon: _currentPosition?.longitude, accuracyMeters: _currentPosition?.accuracy, offlineMode: true, + skipSessionStore: true, ); if (registerResult == null || registerResult['success'] != true) { final regReason = registerResult?['reason'] as String? ?? 'unknown'; - debugError('[API] Offline upload Stage 2 registration failed: $regReason'); + debugError('[OFFLINE] Stage 2 registration failed: $regReason'); return OfflineUploadResult.authFailed; } - debugLog('[APP] Stage 2 succeeded: device registered for offline upload'); + debugLog('[OFFLINE] Stage 2 succeeded: device registered for offline upload'); effectiveAuth = registerResult; } else { - debugError('[API] Offline upload auth failed: $reason'); + debugError('[OFFLINE] Auth failed: $reason'); return OfflineUploadResult.authFailed; } } - debugLog('[APP] Offline upload authenticated, session: ${effectiveAuth!['session_id']}'); + // Extract session_id into local variable — never stored in shared state + final offlineSessionId = effectiveAuth!['session_id'] as String?; + if (offlineSessionId == null) { + debugError('[OFFLINE] Auth succeeded but no session_id in response'); + return OfflineUploadResult.authFailed; + } + + debugLog('[OFFLINE] Authenticated with isolated session: $offlineSessionId'); // Delay after auth before posting await Future.delayed(const Duration(seconds: 1)); - // 4. Upload pings in batches of 50 + // 4. Upload pings in batches of 50 using isolated session const batchSize = 50; var uploadedCount = 0; var failedBatches = 0; + final totalBatches = (pings.length + batchSize - 1) ~/ batchSize; for (var i = 0; i < pings.length; i += batchSize) { + final batchNum = (i ~/ batchSize) + 1; + onProgress?.call('Batch $batchNum/$totalBatches'); + final batch = pings.skip(i).take(batchSize).toList(); - final result = await _apiService.uploadBatch(batch); + final result = await _apiService.uploadBatchWithSessionId(batch, offlineSessionId); if (result == UploadResult.success) { uploadedCount += batch.length; - debugLog('[APP] Uploaded batch ${(i ~/ batchSize) + 1}: ${batch.length} pings'); + debugLog('[OFFLINE] Uploaded batch $batchNum: ${batch.length} pings'); } else { failedBatches++; - debugError('[APP] Failed to upload batch ${(i ~/ batchSize) + 1}'); + debugError('[OFFLINE] Failed to upload batch $batchNum'); } } // Delay after posting before disconnect await Future.delayed(const Duration(seconds: 1)); - // 5. Release API session + // 5. Release isolated API session (does not clear shared state) + onProgress?.call('Finalizing...'); await _apiService.requestAuth( reason: 'disconnect', publicKey: publicKey, + sessionId: offlineSessionId, ); - debugLog('[APP] Offline upload session released'); + debugLog('[OFFLINE] Isolated upload session released'); // 6. Mark session as uploaded (don't delete) if all batches succeeded if (failedBatches == 0) { await _offlineSessionService.markAsUploaded(filename); - debugLog('[API] Uploaded ${pings.length} pings from $filename'); + debugLog('[OFFLINE] Uploaded ${pings.length} pings from $filename'); notifyListeners(); return OfflineUploadResult.success; } else { - debugWarn('[API] Partial upload: $uploadedCount/${pings.length} pings from $filename'); + debugWarn('[OFFLINE] Partial upload: $uploadedCount/${pings.length} pings from $filename'); notifyListeners(); return OfflineUploadResult.partialFailure; } diff --git a/lib/screens/log_screen.dart b/lib/screens/log_screen.dart index 53598dd..97267e0 100644 --- a/lib/screens/log_screen.dart +++ b/lib/screens/log_screen.dart @@ -501,7 +501,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( label, style: TextStyle( - fontSize: 12, + fontSize: 13, fontWeight: active ? FontWeight.w600 : FontWeight.w500, color: active ? color : Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.6), ), @@ -509,17 +509,20 @@ class _AllPingsTabState extends State<_AllPingsTab> { if (count > 0) ...[ const SizedBox(width: 4), Container( - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), + constraints: const BoxConstraints(minWidth: 18, minHeight: 16), + padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), decoration: BoxDecoration( color: active ? color : Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(8), ), + alignment: Alignment.center, child: Text( count > 99 ? '99+' : count.toString(), style: const TextStyle( - fontSize: 9, + fontSize: 10, fontWeight: FontWeight.bold, color: Colors.white, + height: 1.0, ), ), ), @@ -560,8 +563,8 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Text( label, style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, + fontSize: 12, + fontWeight: FontWeight.bold, color: color, ), ), @@ -583,7 +586,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { child: Text( value, style: TextStyle( - fontSize: 10, + fontSize: 11, fontWeight: FontWeight.w600, color: color, fontFamily: 'monospace', @@ -618,7 +621,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( 'No repeaters heard', style: TextStyle( - fontSize: 11, + fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, fontStyle: FontStyle.italic, ), @@ -666,7 +669,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), child: Row( children: [ - RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 11, width: 60), + RepeaterIdChip(repeaterId: event.repeaterId, fontSize: 14, width: 60), Expanded(child: Center(child: _buildChip(event.snr?.toStringAsFixed(1) ?? '-', snrColor))), Expanded(child: Center(child: _buildChip(event.rssi != null ? '${event.rssi}' : '-', rssiColor))), ], @@ -722,7 +725,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), child: Row( children: [ - RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 11, width: 60), + RepeaterIdChip(repeaterId: entry.repeaterId, fontSize: 14, width: 60), Expanded(child: Center(child: _buildChip(entry.snr?.toStringAsFixed(1) ?? '-', snrColor))), Expanded(child: Center(child: _buildChip(entry.rssi != null ? '${entry.rssi}' : '-', rssiColor))), ], @@ -789,7 +792,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( 'No nodes discovered', style: TextStyle( - fontSize: 11, + fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, fontStyle: FontStyle.italic, ), @@ -824,11 +827,11 @@ class _AllPingsTabState extends State<_AllPingsTab> { width: 70, child: Row( children: [ - Flexible(child: RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 11)), + Flexible(child: RepeaterIdChip(repeaterId: node.repeaterId, fontSize: 14)), Text( node.nodeTypeLabel, style: const TextStyle( - fontSize: 9, + fontSize: 11, fontWeight: FontWeight.w500, color: Color(0xFF7B68EE), ), @@ -896,7 +899,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( 'No response', style: TextStyle( - fontSize: 11, + fontSize: 12, color: colorScheme.onSurfaceVariant, fontStyle: FontStyle.italic, ), @@ -918,7 +921,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), child: Row( children: [ - SizedBox(width: 70, child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 11)), + SizedBox(width: 70, child: RepeaterIdChip(repeaterId: entry.targetRepeaterId, fontSize: 14)), Expanded(child: Center(child: _buildChip(entry.localSnr?.toStringAsFixed(1) ?? '-', rxSnrColor))), Expanded(child: Center(child: _buildChip(entry.localRssi != null ? '${entry.localRssi}' : '-', rssiColor))), Expanded(child: Center(child: _buildChip(entry.remoteSnr?.toStringAsFixed(1) ?? '-', txSnrColor))), @@ -946,7 +949,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( timeString, style: TextStyle( - fontSize: 12, + fontSize: 14, fontWeight: FontWeight.w600, fontFamily: 'monospace', color: Theme.of(context).colorScheme.onSurface, @@ -958,7 +961,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { Text( locationString, style: TextStyle( - fontSize: 11, + fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, fontFamily: 'monospace', ), @@ -972,7 +975,7 @@ class _AllPingsTabState extends State<_AllPingsTab> { text, textAlign: center ? TextAlign.center : TextAlign.left, style: TextStyle( - fontSize: 10, + fontSize: 12, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.onSurfaceVariant, ), diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index e0d144f..c99446f 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -233,13 +233,16 @@ class _SettingsScreenState extends State { children: [ const Flexible(child: Text('Hybrid Mode', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), - GestureDetector( - onTap: () => _showHybridModeInfo(context), - child: Icon( + IconButton( + onPressed: () => _showHybridModeInfo(context), + icon: Icon( Icons.info_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant, ), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), ), ], ), @@ -260,13 +263,16 @@ class _SettingsScreenState extends State { children: [ const Flexible(child: Text('Discovery Drop', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), - GestureDetector( - onTap: () => _showDiscDropInfo(context), - child: Icon( + IconButton( + onPressed: () => _showDiscDropInfo(context), + icon: Icon( Icons.info_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant, ), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), ), ], ), @@ -278,7 +284,11 @@ class _SettingsScreenState extends State { : const Text('Count failed discoveries as failed pings'), value: appState.enforceDiscDrop ? true : prefs.discDropEnabled, onChanged: (isAutoMode || appState.enforceDiscDrop) ? null : (value) { - appState.updatePreferences(prefs.copyWith(discDropEnabled: value)); + if (value == true) { + _showDiscDropEnableConfirmation(context, appState); + } else { + appState.updatePreferences(prefs.copyWith(discDropEnabled: false)); + } }, ), ]), @@ -336,13 +346,16 @@ class _SettingsScreenState extends State { children: [ const Flexible(child: Text('TX Bytes', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), - GestureDetector( - onTap: () => _showHopBytesInfo(context), - child: Icon( + IconButton( + onPressed: () => _showHopBytesInfo(context), + icon: Icon( Icons.info_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant, ), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), ), ], ), @@ -383,13 +396,16 @@ class _SettingsScreenState extends State { children: [ const Flexible(child: Text('Trace Bytes', overflow: TextOverflow.ellipsis)), const SizedBox(width: 4), - GestureDetector( - onTap: () => _showTraceBytesInfo(context), - child: Icon( + IconButton( + onPressed: () => _showTraceBytesInfo(context), + icon: Icon( Icons.info_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant, ), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), ), ], ), @@ -425,16 +441,22 @@ class _SettingsScreenState extends State { children: [ const Flexible(child: Text('Delete Channel on Disconnect')), const SizedBox(width: 4), - GestureDetector( - onTap: () => _showDeleteChannelInfo(context), - child: Icon( + IconButton( + onPressed: () => _showDeleteChannelInfo(context), + icon: Icon( Icons.info_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant, ), + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), ), ], ), + subtitle: Text(prefs.deleteChannelOnDisconnect + ? 'Removes #wardriving channel from device' + : 'Keeps #wardriving channel on device'), value: prefs.deleteChannelOnDisconnect, onChanged: (value) { appState.updatePreferences(prefs.copyWith(deleteChannelOnDisconnect: value)); @@ -493,6 +515,7 @@ class _SettingsScreenState extends State { else ...appState.offlineSessions.map((session) => _OfflineSessionTile( session: session, + uploadEnabled: !appState.isUploadingOfflineSession, onUpload: () => _uploadOfflineSession(context, appState, session.filename), onDelete: () => _confirmDeleteOfflineSession(context, appState, session.filename), onDownload: () => _downloadOfflineSession(context, appState, session.filename), @@ -1157,6 +1180,51 @@ class _SettingsScreenState extends State { ); } + void _showDiscDropEnableConfirmation(BuildContext context, AppStateProvider appState) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.signal_wifi_off, size: 24), + SizedBox(width: 8), + Text('Discovery Drop'), + ], + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'When enabled, failed discovery requests (no repeater responded) are reported to the API as failed pings, helping identify dead zones in the mesh network.', + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 12), + Text( + 'Discovery requests require Repeater firmware 1.10+. If the majority of the mesh is not on this version, it may produce false "no coverage" areas/failed pings.', + style: TextStyle(fontSize: 13, color: Colors.amber), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + appState.updatePreferences( + appState.preferences.copyWith(discDropEnabled: true), + ); + }, + child: const Text('Enable'), + ), + ], + ), + ); + } + void _showDeleteChannelInfo(BuildContext context) { showDialog( context: context, @@ -1332,13 +1400,22 @@ class _SettingsScreenState extends State { } final tile = RadioListTile( - title: Text('$interval seconds'), + title: Text( + '$interval seconds', + style: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold), + ), subtitle: isDisabled ? const Text( 'Set by Regional Admin — slower intervals reduce congestion in your region', - style: TextStyle(color: Colors.amber), + style: TextStyle(fontSize: 12, color: Colors.amber), ) - : Text(description), + : Text( + description, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), value: interval, ); @@ -1563,31 +1640,61 @@ class _SettingsScreenState extends State { } Future _uploadOfflineSession(BuildContext context, AppStateProvider appState, String filename) async { - // Show loading indicator - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Row( - children: [ - SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white), - ), - SizedBox(width: 12), - Text('Uploading session...'), - ], + // Progress text notifier for updating dialog without rebuilding screen + final progressNotifier = ValueNotifier('Authenticating...'); + + // Show non-dismissible progress dialog + showDialog( + context: context, + barrierDismissible: false, + builder: (dialogContext) => PopScope( + canPop: false, + child: AlertDialog( + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + const Text( + 'Uploading session...', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + ), + const SizedBox(height: 4), + Text( + filename, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 12, color: Colors.grey.shade600), + ), + const SizedBox(height: 8), + ValueListenableBuilder( + valueListenable: progressNotifier, + builder: (_, status, __) => Text( + status, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 12, color: Colors.grey.shade500), + ), + ), + ], + ), ), - duration: Duration(seconds: 30), // Will be dismissed when upload completes ), ); - final result = await appState.uploadOfflineSessionWithAuth(filename); + final result = await appState.uploadOfflineSessionWithAuth( + filename, + onProgress: (status) => progressNotifier.value = status, + ); + // Close progress dialog if (context.mounted) { - // Dismiss loading indicator - ScaffoldMessenger.of(context).hideCurrentSnackBar(); + Navigator.of(context).pop(); + } - // Show result + progressNotifier.dispose(); + + if (context.mounted) { + // Show result via SnackBar String message; Color backgroundColor; @@ -1612,6 +1719,10 @@ class _SettingsScreenState extends State { message = 'Partial upload - some pings failed'; backgroundColor = Colors.orange; break; + case OfflineUploadResult.uploadInProgress: + message = 'Another upload is already in progress'; + backgroundColor = Colors.orange; + break; } ScaffoldMessenger.of(context).showSnackBar( @@ -1948,12 +2059,14 @@ class _BackgroundModeToggleState extends State<_BackgroundModeToggle> /// Widget for displaying an offline session in the list class _OfflineSessionTile extends StatelessWidget { final OfflineSession session; + final bool uploadEnabled; final VoidCallback onUpload; final VoidCallback onDelete; final VoidCallback onDownload; const _OfflineSessionTile({ required this.session, + this.uploadEnabled = true, required this.onUpload, required this.onDelete, required this.onDownload, @@ -2000,9 +2113,9 @@ class _OfflineSessionTile extends StatelessWidget { if (!isUploaded) IconButton( icon: const Icon(Icons.cloud_upload), - onPressed: onUpload, + onPressed: uploadEnabled ? onUpload : null, tooltip: 'Upload session', - color: Colors.green, + color: uploadEnabled ? Colors.green : Colors.grey, ), // Delete button - always available IconButton( diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index aed7fb7..064c25a 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -224,6 +224,8 @@ class ApiService { /// @param publicKey Device public key (for existing auth flow) /// @param contactUri Signed contact URI (for registration flow) /// @param offlineMode Set to true when uploading offline session data + /// @param skipSessionStore When true, does not write to shared _sessionId/_txAllowed/etc. Caller manages session locally. + /// @param sessionId Explicit session ID for disconnect. When provided, disconnect uses this instead of _sessionId and skips _clearSession(). /// @returns Map with success, session_id, tx_allowed, rx_allowed, expires_at, reason, message Future?> requestAuth({ required String reason, @@ -238,6 +240,8 @@ class ApiService { double? lon, double? accuracyMeters, bool offlineMode = false, + bool skipSessionStore = false, + String? sessionId, }) async { final stopwatch = Stopwatch()..start(); try { @@ -278,8 +282,8 @@ class ApiService { 'timestamp': DateTime.now().millisecondsSinceEpoch ~/ 1000, }; } else { - // For disconnect: add session_id - payload['session_id'] = _sessionId; + // For disconnect: use explicit sessionId if provided, otherwise shared _sessionId + payload['session_id'] = sessionId ?? _sessionId; } final response = await _client.post( @@ -316,66 +320,71 @@ class ApiService { // Store session info on successful connect or register // Note: 'register' now returns full auth response directly (no retry needed) if ((reason == 'connect' || reason == 'register') && data['success'] == true) { - _sessionId = data['session_id'] as String?; - _txAllowed = data['tx_allowed'] == true; - _rxAllowed = data['rx_allowed'] == true; - _sessionExpiresAt = data['expires_at'] as int?; - - // Parse channels array from auth response - final channelsData = data['channels']; - if (channelsData is List) { - _channels = channelsData.cast().toList(); - debugLog('[API] Regional channels: $_channels'); - } else { - _channels = []; - } + if (!skipSessionStore) { + _sessionId = data['session_id'] as String?; + _txAllowed = data['tx_allowed'] == true; + _rxAllowed = data['rx_allowed'] == true; + _sessionExpiresAt = data['expires_at'] as int?; + + // Parse channels array from auth response + final channelsData = data['channels']; + if (channelsData is List) { + _channels = channelsData.cast().toList(); + debugLog('[API] Regional channels: $_channels'); + } else { + _channels = []; + } - // Parse scopes array from auth response - final scopesData = data['scopes']; - if (scopesData is List && scopesData.isNotEmpty) { - _scopes = scopesData.cast().toList(); - debugLog('[API] Regional scopes: $_scopes'); - } else { - _scopes = []; - } + // Parse scopes array from auth response + final scopesData = data['scopes']; + if (scopesData is List && scopesData.isNotEmpty) { + _scopes = scopesData.cast().toList(); + debugLog('[API] Regional scopes: $_scopes'); + } else { + _scopes = []; + } - // Parse enforce_hybrid flag from auth response - _enforceHybrid = data['enforce_hybrid'] == true; - if (_enforceHybrid) { - debugLog('[API] Regional admin enforces hybrid mode'); - } + // Parse enforce_hybrid flag from auth response + _enforceHybrid = data['enforce_hybrid'] == true; + if (_enforceHybrid) { + debugLog('[API] Regional admin enforces hybrid mode'); + } - // Parse disc_drop flag from auth response - _enforceDiscDrop = data['disc_drop'] == true; - if (_enforceDiscDrop) { - debugLog('[API] Regional admin enforces discovery drop'); - } + // Parse disc_drop flag from auth response + _enforceDiscDrop = data['disc_drop'] == true; + if (_enforceDiscDrop) { + debugLog('[API] Regional admin enforces discovery drop'); + } - // Parse min_mode_interval from auth response - final minInterval = data['min_mode_interval']; - if (minInterval is int && minInterval > 0) { - _minModeInterval = minInterval; - debugLog('[API] Regional admin min interval: ${_minModeInterval}s'); - } else { - _minModeInterval = 15; - } + // Parse min_mode_interval from auth response + final minInterval = data['min_mode_interval']; + if (minInterval is int && minInterval > 0) { + _minModeInterval = minInterval; + debugLog('[API] Regional admin min interval: ${_minModeInterval}s'); + } else { + _minModeInterval = 15; + } - // Parse hop_bytes from auth response - final hopBytes = data['hop_bytes']; - if (hopBytes is int && hopBytes >= 1 && hopBytes <= 3) { - _apiHopBytes = hopBytes; - if (_apiHopBytes > 1) { - debugLog('[API] Regional admin enforces $_apiHopBytes-byte paths'); + // Parse hop_bytes from auth response + final hopBytes = data['hop_bytes']; + if (hopBytes is int && hopBytes >= 1 && hopBytes <= 3) { + _apiHopBytes = hopBytes; + if (_apiHopBytes > 1) { + debugLog('[API] Regional admin enforces $_apiHopBytes-byte paths'); + } + } else { + _apiHopBytes = 1; } - } else { - _apiHopBytes = 1; - } - // Note: Heartbeat is enabled by AppStateProvider when auto mode starts - // (not on initial auth, since heartbeat is only for auto mode) + // Note: Heartbeat is enabled by AppStateProvider when auto mode starts + // (not on initial auth, since heartbeat is only for auto mode) + } } else if (reason == 'disconnect') { - // Clear session on disconnect - _clearSession(); + // Only clear shared session when no explicit sessionId was provided + // (explicit sessionId means caller manages its own session lifecycle) + if (sessionId == null) { + _clearSession(); + } } return data; @@ -861,6 +870,112 @@ class ApiService { } } + /// Submit wardrive data using an explicit session ID (for offline uploads) + /// Does NOT read/write shared _sessionId, _sessionExpiresAt, or heartbeat state + Future?> submitWardriveDataWithSessionId( + List> entries, + String sessionId, + ) async { + final stopwatch = Stopwatch()..start(); + try { + final payload = { + 'key': apiKey, + 'session_id': sessionId, + 'data': entries, + }; + + final response = await _client.post( + Uri.parse(wardriveEndpoint), + headers: {'Content-Type': 'application/json'}, + body: json.encode(payload), + ).timeout(const Duration(seconds: 30)); + + stopwatch.stop(); + + if (response.statusCode != 200) { + debugError('[API] /wardrive-api.php/wardrive (offline) returned HTTP ${response.statusCode}'); + debugError('[API] Response body: ${response.body.isEmpty ? '(empty)' : response.body}'); + } + + Map data; + try { + data = json.decode(response.body) as Map; + } on FormatException { + debugError('[API] Non-JSON response from /wardrive offline (HTTP ${response.statusCode}): ' + '${response.body.length > 500 ? response.body.substring(0, 500) : response.body}'); + rethrow; + } + + final antennaSummary = entries.map((e) => + '${e['type']}:external_antenna=${e['external_antenna']}' + ).join(', '); + _logApiCall( + endpoint: '/wardrive-api.php/wardrive (offline)', + method: 'POST', + stopwatch: stopwatch, + statusCode: response.statusCode, + request: {'data': '${entries.length} items', 'items': antennaSummary}, + response: data, + ); + + // Do NOT update shared _sessionExpiresAt or schedule heartbeat + return data; + } catch (e) { + stopwatch.stop(); + debugError('[API] POST /wardrive-api.php/wardrive (offline) failed: $e'); + return null; + } + } + + /// Upload batch using explicit session ID (for offline uploads) + /// Returns UploadResult only — does NOT call _clearSession(), onSessionError, or onMaintenanceMode + Future uploadBatchWithSessionId( + List> pings, + String sessionId, + ) async { + if (pings.isEmpty) return UploadResult.success; + + try { + final result = await submitWardriveDataWithSessionId(pings, sessionId); + + if (result == null) { + debugError('[API] Offline upload batch failed: no response'); + return UploadResult.retryable; + } + + if (result['success'] == true) { + debugLog('[API] Offline upload batch SUCCESS: ${pings.length} items'); + return UploadResult.success; + } + + final reason = result['reason'] as String?; + + // For offline uploads, session/auth errors are non-retryable but do NOT cascade + const criticalErrors = { + 'session_expired', 'session_invalid', 'session_revoked', 'bad_session', + 'invalid_key', 'unauthorized', 'bad_key', + 'outside_zone', 'zone_full', 'zone_disabled', + }; + if (criticalErrors.contains(reason)) { + debugError('[API] Offline upload batch session error: $reason'); + return UploadResult.nonRetryable; + } + + const nonRetryableErrors = { + 'gps_inaccurate', 'gps_stale', 'invalid_request', 'zone_disabled', 'outofdate', + }; + if (nonRetryableErrors.contains(reason)) { + debugWarn('[API] Offline upload batch non-retryable error: $reason - discarding batch'); + return UploadResult.nonRetryable; + } + + return UploadResult.retryable; + } catch (e) { + debugError('[API] Offline upload batch exception: $e'); + return UploadResult.retryable; + } + } + /// Dispose of resources void dispose() { _heartbeatTimer?.cancel(); From eccc88d20978cee5312bc935b4154e507ecace04 Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Tue, 17 Mar 2026 22:02:42 -0400 Subject: [PATCH 55/57] Fixed trace mode chip and trace icon --- lib/screens/home_screen.dart | 11 +++++++++++ lib/widgets/ping_controls.dart | 4 ++-- lib/widgets/status_bar.dart | 13 +++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 6050b5c..d984a98 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -175,6 +175,14 @@ class _HomeScreenState extends State { onTap: withTapHandlers ? () => _showInfoPopup('disc', appState) : null, ), const SizedBox(width: 8), + // Trace count + _buildAppBarStatChip( + Icons.route, + appState.pingStats.traceCount, + Colors.cyan, + onTap: withTapHandlers ? () => _showInfoPopup('trace', appState) : null, + ), + const SizedBox(width: 8), // Upload count _buildAppBarStatChip( Icons.cloud_done, @@ -331,6 +339,9 @@ class _HomeScreenState extends State { case 'disc': return ('Discovery Requests', 'Discovery request packets we have sent out.', Icons.radar, const Color(0xFF7B68EE)); + case 'trace': + return ('Trace Responses', 'Trace path requests that received a response from the target repeater.', Icons.route, Colors.cyan); + case 'upload': return ('Uploaded', 'Pings sent to MeshMapper servers. Your data helps build the community coverage map!', Icons.cloud_done, Colors.teal); diff --git a/lib/widgets/ping_controls.dart b/lib/widgets/ping_controls.dart index 5c4f2e6..805417d 100644 --- a/lib/widgets/ping_controls.dart +++ b/lib/widgets/ping_controls.dart @@ -575,7 +575,7 @@ class _TargetedPingSectionState extends State<_TargetedPingSection> { child: Row( children: [ Icon( - Icons.gps_fixed, + Icons.route, size: 18, color: effectiveColor, ), @@ -896,7 +896,7 @@ class _CompactPingControlsState extends State { // Build trace mode button (only used when hasTargetRepeaterId) final traceModeButton = _CompactActionButton( - icon: Icons.gps_fixed, + icon: Icons.route, label: _getTraceModeLabel( isTargetedRunning: isTargetedRunning, discoveryWindowActive: discoveryWindowActive, diff --git a/lib/widgets/status_bar.dart b/lib/widgets/status_bar.dart index 90fa4af..563d28f 100644 --- a/lib/widgets/status_bar.dart +++ b/lib/widgets/status_bar.dart @@ -158,6 +158,9 @@ class _StatusBarState extends State { case 'disc': return ('Discovery Requests', 'Discovery requests we have heard a response for.', Icons.radar, const Color(0xFF7B68EE)); + case 'trace': + return ('Trace Responses', 'Trace path requests that received a response from the target repeater.', Icons.route, Colors.cyan); + case 'upload': return ('Uploaded', 'Pings sent to MeshMapper servers. Your data helps build the community coverage map!', Icons.cloud_done, Colors.teal); @@ -262,6 +265,16 @@ class _StatusBarState extends State { const SizedBox(width: 8), + // Trace count chip (animated) + _AnimatedStatChip( + icon: Icons.route, + value: appState.pingStats.traceCount, + color: Colors.cyan, + onTap: () => _showInfoPopup(context, 'trace'), + ), + + const SizedBox(width: 8), + // Uploaded count chip (animated) _AnimatedStatChip( icon: Icons.cloud_done, From e4e9faededd7ac8ed12b3859f5de4d668d2cec6a Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Thu, 19 Mar 2026 21:24:37 -0400 Subject: [PATCH 56/57] ### New Features - Persistent radio power overrides: custom TX power settings are now saved per device, similar to antenna selection. On connect, your previously set power override is automatically applied with a visual indicator showing it's been overridden. A "Reset to Auto" button in the power selector restores the auto-detected power for your device model. ### Improvements - Redesigned the Top Heard overlay. Now shows the repeaters that heard your most recent ping sorted by SNR, with color-coded indicators per ping type (green for TX, purple for Discovery, cyan for Trace, blue for RX). Top 3 slots show the best results from your latest ping and fully replace on each new ping. A separate RX slot shows the strongest passively overheard repeater within a rolling 5-second window. Overlay clears on auto-ping stop, mode switch, disconnect, or log clear. --- lib/providers/app_state_provider.dart | 162 +++++++++++++++++++++----- lib/screens/connection_screen.dart | 48 ++++++-- lib/widgets/map_widget.dart | 106 +++++++++++------ 3 files changed, 244 insertions(+), 72 deletions(-) diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 2f98a53..745b96f 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -52,6 +52,9 @@ enum AutoMode { targeted, } +/// Ping type for the top-heard overlay dots +enum OverlayPingType { tx, disc, trace, rx } + /// Result of uploading an offline session enum OfflineUploadResult { /// Upload completed successfully @@ -169,7 +172,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { final List _traceLogEntries = []; // Top repeaters overlay — updated live on each ping event - List<({String repeaterId, double snr})> _topRepeatersOverlay = []; + List<({String repeaterId, double snr, OverlayPingType type})> _topRepeatersOverlay = []; + ({String repeaterId, double snr})? _rxOverlaySlot; + Timer? _rxOverlayWindowTimer; // Targeted mode state String? _targetRepeaterId; @@ -191,6 +196,13 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { bool _antennaRestoredFromDevice = false; bool get antennaRestoredFromDevice => _antennaRestoredFromDevice; + /// Per-device power overrides: maps companion name → {powerLevel, txPower} + Map> _devicePowerOverrides = {}; + + /// Whether the current power setting was auto-restored from a saved override + bool _powerRestoredFromDevice = false; + bool get powerRestoredFromDevice => _powerRestoredFromDevice; + // Remembered device for quick reconnection (mobile only) RememberedDevice? _rememberedDevice; @@ -345,14 +357,14 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { List get txPings => List.unmodifiable(_txPings); List get rxPings => List.unmodifiable(_rxPings); - /// Top 3 repeaters by best SNR (1-byte IDs only) across TX echoes and RX observations - List<({String repeaterId, double snr})> get topRepeatersBySnr => _topRepeatersOverlay; + /// Top 3 repeaters by best SNR from TX/DISC/Trace pings + List<({String repeaterId, double snr, OverlayPingType type})> get topRepeatersBySnr => _topRepeatersOverlay; + /// Best RX observation in the current 5-second window + ({String repeaterId, double snr})? get rxOverlaySlot => _rxOverlaySlot; - /// Update the top repeaters overlay with results from the latest ping. - /// New repeaters from this ping take priority (sorted by best SNR first). - /// Remaining slots are filled with carryover from the previous display. - void _updateTopRepeaters(List<({String repeaterId, double snr})> current) { - // Deduplicate current entries, keeping best SNR per repeater + /// Update the top repeaters overlay with results from the latest TX/DISC/Trace ping. + /// Replaces all 3 slots entirely (no carryover from previous pings). + void _updateTopRepeaters(List<({String repeaterId, double snr})> current, OverlayPingType type) { final bestSnr = {}; for (final r in current) { final key = r.repeaterId.toUpperCase(); @@ -361,21 +373,34 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } final fresh = bestSnr.entries - .map((e) => (repeaterId: e.key, snr: e.value)) + .map((e) => (repeaterId: e.key, snr: e.value, type: type)) .toList() ..sort((a, b) => b.snr.compareTo(a.snr)); + _topRepeatersOverlay = fresh.take(3).toList(); + } - if (fresh.length >= 3) { - _topRepeatersOverlay = fresh.take(3).toList(); + /// Update the RX overlay slot with a 5-second rolling window (best SNR wins). + void _updateRxOverlaySlot(String repeaterId, double snr) { + final entry = (repeaterId: repeaterId.toUpperCase(), snr: snr); + if (_rxOverlayWindowTimer?.isActive ?? false) { + if (_rxOverlaySlot == null || snr > _rxOverlaySlot!.snr) { + _rxOverlaySlot = entry; + } } else { - // Fill remaining slots with previous entries not already in fresh - final freshIds = fresh.map((r) => r.repeaterId).toSet(); - final carryover = _topRepeatersOverlay - .where((r) => !freshIds.contains(r.repeaterId)) - .toList(); - _topRepeatersOverlay = [...fresh, ...carryover].take(3).toList(); + _rxOverlaySlot = entry; + _rxOverlayWindowTimer = Timer(const Duration(seconds: 5), () { + // Window closed — slot stays until next RX or cleared + }); } } + + /// Clear all overlay state (top 3 + RX slot). + void _clearOverlayState() { + _topRepeatersOverlay = []; + _rxOverlaySlot = null; + _rxOverlayWindowTimer?.cancel(); + _rxOverlayWindowTimer = null; + } List get txLogEntries => List.unmodifiable(_txLogEntries); List get rxLogEntries => List.unmodifiable(_rxLogEntries); List get discLogEntries => List.unmodifiable(_discLogEntries); @@ -616,6 +641,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[INIT] Loading preferences...'); await _loadPreferences(); await _loadDeviceAntennaPreferences(); + await _loadDevicePowerOverrides(); // Load last known GPS position for map centering await _loadLastPosition(); @@ -1162,8 +1188,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { powerLevel: device.power, txPower: device.txPower, autoPowerSet: true, // Indicates power was auto-detected from device model + powerLevelSet: false, // Clear stale manual flag from previous session ); - // TODO: Persist to SharedPreferences when implemented notifyListeners(); debugLog('[MODEL] Device recognized: ${device.shortName} - reporting ${device.power}W in API calls'); } @@ -1324,8 +1350,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { )); if (_rxLogEntries.length > _maxLogEntries) _rxLogEntries.removeAt(0); - // Update top repeaters overlay with this RX observation - _updateTopRepeaters([(repeaterId: ping.repeaterId.toUpperCase(), snr: ping.snr)]); + // Update RX overlay slot with this RX observation + _updateRxOverlaySlot(ping.repeaterId, ping.snr); notifyListeners(); }; @@ -1402,7 +1428,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _updateTopRepeaters(existingEvents .where((e) => e.snr != null) .map((e) => (repeaterId: e.repeaterId.toUpperCase(), snr: e.snr!)) - .toList()); + .toList(), OverlayPingType.tx); debugLog('[APP] Calling notifyListeners() to update UI'); notifyListeners(); @@ -1452,7 +1478,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Update top repeaters overlay with all discovered nodes from this ping _updateTopRepeaters(discPing.discoveredNodes .map((n) => (repeaterId: n.repeaterId.toUpperCase(), snr: n.localSnr)) - .toList()); + .toList(), OverlayPingType.disc); notifyListeners(); }; @@ -1652,6 +1678,21 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { notifyListeners(); } + // Restore per-device power override if previously saved + if (resolvedName != null && _devicePowerOverrides.containsKey(resolvedName)) { + final saved = _devicePowerOverrides[resolvedName]!; + _preferences = _preferences.copyWith( + powerLevel: (saved['powerLevel'] as num).toDouble(), + txPower: (saved['txPower'] as num).toInt(), + autoPowerSet: false, + powerLevelSet: true, + ); + _powerRestoredFromDevice = true; + _savePreferences(); + debugLog('[APP] Restored power override for "$resolvedName": ${saved['powerLevel']}W'); + notifyListeners(); + } + // Log connection status based on TX/RX permissions if (hasApiSession) { if (txAllowed && rxAllowed) { @@ -1785,9 +1826,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Created IMMEDIATE RX pin for repeater: ${observation.repeaterId} ' 'at ${observation.lat.toStringAsFixed(5)},${observation.lon.toStringAsFixed(5)} ' '(batch tracking: ${_currentBatchRepeaters.length} repeaters, rxCount: ${_pingStats.rxCount})'); - // Update top repeaters overlay immediately + // Update RX overlay slot immediately if (observation.snr != null) { - _updateTopRepeaters([(repeaterId: repeaterKey, snr: observation.snr!)]); + _updateRxOverlaySlot(repeaterKey, observation.snr!); } // Play receive sound for new RX observation _audioService.playReceiveSound(); @@ -1894,9 +1935,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Added RX log entry: repeater=${entry.repeaterId}, ' 'snr=${entry.snr ?? 'null'}, pathLen=${entry.pathLength}'); - // Update top repeaters overlay with this RX observation + // Update RX overlay slot with this RX observation if (entry.snr != null) { - _updateTopRepeaters([(repeaterId: entry.repeaterId.toUpperCase(), snr: entry.snr!)]); + _updateRxOverlaySlot(entry.repeaterId, entry.snr!); } // Note: RX count is incremented in onObservation when pin is created (immediate feedback) @@ -2183,6 +2224,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _isAnonymousRenamed = false; _originalDeviceName = null; + // Clear top-heard overlay + _clearOverlayState(); + // Existing cleanup _meshCoreConnection?.dispose(); _meshCoreConnection = null; @@ -2359,8 +2403,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _reconnectAttempt = 0; _autoPingWasEnabled = false; - // Reset antenna setting so user must choose again on next connect + // Reset antenna and power settings so user must choose again on next connect _antennaRestoredFromDevice = false; + _powerRestoredFromDevice = false; _preferences = _preferences.copyWith(externalAntenna: false, externalAntennaSet: false); _savePreferences(); @@ -2499,6 +2544,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _offlineContactUri = null; _displayDeviceName = null; _antennaRestoredFromDevice = false; + _powerRestoredFromDevice = false; _preferences = _preferences.copyWith(externalAntenna: false, externalAntennaSet: false); _savePreferences(); _currentNoiseFloor = null; @@ -2666,6 +2712,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _autoPingEnabled = false; _idleAutoStopReference = null; + // Clear top-heard overlay on stop + _clearOverlayState(); + // Start 5-second shared cooldown for TX modes (Active/Hybrid), not Passive Mode // Passive Mode is listening only, no cooldown needed if (isTxMode) { @@ -2698,6 +2747,8 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Stop countdown timers when switching modes _autoPingTimer.stop(); _rxWindowTimer.stop(); + // Clear top-heard overlay on mode switch + _clearOverlayState(); // Save offline session if offline mode is enabled if (_preferences.offlineMode) { await _saveOfflineSession(); @@ -2774,6 +2825,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { void clearPings() { _txPings.clear(); _rxPings.clear(); + _clearOverlayState(); _pingService?.resetStats(); notifyListeners(); } @@ -2785,6 +2837,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _discLogEntries.clear(); _traceLogEntries.clear(); _errorLogEntries.clear(); + _clearOverlayState(); notifyListeners(); } @@ -2811,7 +2864,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { // Truncate 4-byte trace IDs to 3 bytes (6 hex chars) to fit overlay final id = entry.targetRepeaterId.toUpperCase(); final displayId = id.length > 6 ? id.substring(0, 6) : id; - _updateTopRepeaters([(repeaterId: displayId, snr: entry.localSnr!)]); + _updateTopRepeaters([(repeaterId: displayId, snr: entry.localSnr!)], OverlayPingType.trace); } notifyListeners(); @@ -3530,8 +3583,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _preferences = preferences; - // Clear restored flag — user is making a manual choice now + // Clear restored flags — user is making a manual choice now _antennaRestoredFromDevice = false; + _powerRestoredFromDevice = false; // Persist antenna choice per device name (use original name, not "Anonymous") final deviceName = _isAnonymousRenamed ? _originalDeviceName : displayDeviceName; @@ -3541,6 +3595,22 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { debugLog('[APP] Saved antenna preference for "$deviceName": ${preferences.externalAntenna ? "external" : "device"}'); } + // Persist power override per device name + if (deviceName != null && preferences.powerLevelSet && !preferences.autoPowerSet) { + _devicePowerOverrides[deviceName] = { + 'powerLevel': preferences.powerLevel, + 'txPower': preferences.txPower, + }; + _saveDevicePowerOverrides(); + debugLog('[APP] Saved power override for "$deviceName": ${preferences.powerLevel}W'); + } else if (deviceName != null && preferences.autoPowerSet) { + // User re-selected the auto-detected value — clear any saved override + if (_devicePowerOverrides.remove(deviceName) != null) { + _saveDevicePowerOverrides(); + debugLog('[APP] Cleared power override for "$deviceName" (auto-detected selected)'); + } + } + // Propagate RSSI filter setting to live trackers/validators _syncRssiFilterSetting(preferences.disableRssiFilter); @@ -4693,6 +4763,40 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } + // ============================================ + // Device Power Override Persistence + // ============================================ + + /// Load per-device power overrides from Hive storage + Future _loadDevicePowerOverrides() async { + final box = await _openBoxSafely(_preferencesBoxName); + if (box == null) return; + + try { + final raw = box.get('device_power_overrides'); + if (raw != null) { + _devicePowerOverrides = (raw as Map).map( + (key, value) => MapEntry(key.toString(), Map.from(value as Map)), + ); + debugLog('[APP] Loaded power overrides for ${_devicePowerOverrides.length} device(s)'); + } + } catch (e) { + debugLog('[APP] Failed to load device power overrides: $e'); + } + } + + /// Save per-device power overrides to Hive storage + Future _saveDevicePowerOverrides() async { + final box = await _openBoxSafely(_preferencesBoxName); + if (box == null) return; + + try { + await box.put('device_power_overrides', _devicePowerOverrides); + } catch (e) { + debugLog('[APP] Failed to save device power overrides: $e'); + } + } + // ============================================ // Last Connected Device Persistence // ============================================ diff --git a/lib/screens/connection_screen.dart b/lib/screens/connection_screen.dart index 9f3bb88..ce97f87 100644 --- a/lib/screens/connection_screen.dart +++ b/lib/screens/connection_screen.dart @@ -500,6 +500,18 @@ class _ConnectionScreenState extends State with WidgetsBinding fontWeight: FontWeight.bold, ), ), + ] else if (prefs.powerLevelSet && !prefs.autoPowerSet && appState.deviceModel != null) ...[ + const SizedBox(width: 4), + const Icon(Icons.edit, size: 14, color: Colors.orange), + const SizedBox(width: 2), + const Text( + 'Override', + style: TextStyle( + fontSize: 12, + color: Colors.orange, + fontWeight: FontWeight.bold, + ), + ), ], if (!isAutoMode) ...[ const SizedBox(width: 4), @@ -867,6 +879,7 @@ class _ConnectionScreenState extends State with WidgetsBinding powerLevel: value, txPower: PowerLevel.getTxPower(value), autoPowerSet: false, // Clear auto flag on override + powerLevelSet: true, // Mark as manually overridden ), ); Navigator.pop(context); // Close confirmation @@ -899,23 +912,29 @@ class _ConnectionScreenState extends State with WidgetsBinding mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Auto-detection info banner - if (prefs.autoPowerSet && deviceModel != null) + // Auto-detection / override info banner + if (deviceModel != null) Container( padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( - color: Colors.green.withValues(alpha: 0.1), - border: Border.all(color: Colors.green), + color: (prefs.autoPowerSet ? Colors.green : Colors.orange).withValues(alpha: 0.1), + border: Border.all(color: prefs.autoPowerSet ? Colors.green : Colors.orange), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ - const Icon(Icons.auto_awesome, size: 20, color: Colors.green), + Icon( + prefs.autoPowerSet ? Icons.auto_awesome : Icons.edit, + size: 20, + color: prefs.autoPowerSet ? Colors.green : Colors.orange, + ), const SizedBox(width: 8), Expanded( child: Text( - 'Auto-detected: ${deviceModel.shortName} ${deviceModel.power}W', + prefs.autoPowerSet + ? 'Auto-detected: ${deviceModel.shortName} ${deviceModel.power}W' + : 'Override active \u2014 ${deviceModel.shortName} auto-detects as ${deviceModel.power}W', style: const TextStyle(fontSize: 12), ), ), @@ -935,7 +954,7 @@ class _ConnectionScreenState extends State with WidgetsBinding mainAxisSize: MainAxisSize.min, children: PowerLevel.values.map((power) { final isSelected = power == currentPower; - final isRecommended = prefs.autoPowerSet && deviceModel != null && power == deviceModel.power; + final isRecommended = deviceModel != null && power == deviceModel.power; // Create a temp preferences object to get the display string with dBm final tempPrefs = UserPreferences(powerLevel: power); @@ -982,6 +1001,21 @@ class _ConnectionScreenState extends State with WidgetsBinding ], ), actions: [ + if (!prefs.autoPowerSet && deviceModel != null) + TextButton( + onPressed: () { + appState.updatePreferences( + prefs.copyWith( + powerLevel: deviceModel.power, + txPower: deviceModel.txPower, + autoPowerSet: true, + powerLevelSet: false, + ), + ); + Navigator.pop(context); + }, + child: const Text('Reset to Auto', style: TextStyle(color: Colors.green)), + ), TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 9a1617a..7d2e2ef 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -729,10 +729,70 @@ class _MapWidgetState extends State with TickerProviderStateMixin { ); } + /// Color for the overlay ping-type dot + static Color _overlayTypeColor(OverlayPingType type) { + return switch (type) { + OverlayPingType.tx => Colors.green, + OverlayPingType.disc => Colors.purple, + OverlayPingType.trace => Colors.cyan, + OverlayPingType.rx => Colors.blue, + }; + } + + /// Build a single overlay table row with colored dot, repeater ID, and SNR + TableRow _overlayRow(String repeaterId, double snr, Color dotColor) { + return TableRow( + children: [ + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(right: 4), + child: Container( + width: 6, + height: 6, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: dotColor, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 1), + child: Text( + repeaterId, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: Colors.white, + ), + ), + ), + const SizedBox(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 1), + child: Text( + snr.toStringAsFixed(1), + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + color: _snrColor(snr), + ), + ), + ), + ], + ); + } + /// GPS info overlay (top-left corner) - /// Top 3 repeaters by SNR overlay (bottom-right of map) + /// Top heard repeaters overlay (bottom-right of map) Widget _buildTopRepeatersOverlay(AppStateProvider appState) { final topRepeaters = appState.topRepeatersBySnr; + final rxSlot = appState.rxOverlaySlot; + final isEmpty = topRepeaters.isEmpty && rxSlot == null; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), @@ -754,7 +814,7 @@ class _MapWidgetState extends State with TickerProviderStateMixin { ), ), const SizedBox(height: 2), - if (topRepeaters.isEmpty) + if (isEmpty) const Text( '---', style: TextStyle( @@ -763,46 +823,20 @@ class _MapWidgetState extends State with TickerProviderStateMixin { color: Colors.white38, ), ), - if (topRepeaters.isNotEmpty) + if (!isEmpty) Table( defaultColumnWidth: const IntrinsicColumnWidth(), columnWidths: const { - 0: IntrinsicColumnWidth(), - 1: FixedColumnWidth(8), - 2: IntrinsicColumnWidth(), + 0: IntrinsicColumnWidth(), // dot + 1: IntrinsicColumnWidth(), // ID + 2: FixedColumnWidth(8), // spacer + 3: IntrinsicColumnWidth(), // SNR }, children: [ for (final r in topRepeaters) - TableRow( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 1), - child: Text( - r.repeaterId, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: Colors.white, - ), - ), - ), - const SizedBox(), - Padding( - padding: const EdgeInsets.symmetric(vertical: 1), - child: Text( - r.snr.toStringAsFixed(1), - textAlign: TextAlign.right, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - color: _snrColor(r.snr), - ), - ), - ), - ], - ), + _overlayRow(r.repeaterId, r.snr, _overlayTypeColor(r.type)), + if (rxSlot != null) + _overlayRow(rxSlot.repeaterId, rxSlot.snr, _overlayTypeColor(OverlayPingType.rx)), ], ), ], From b7ec8ddf8a1b2f4cbfe556cf4b8a77de783f2b6c Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Fri, 20 Mar 2026 12:10:16 -0400 Subject: [PATCH 57/57] ### New Features - Persistent radio power overrides: custom TX power settings are now saved per device, similar to antenna selection. On connect, your previously set power override is automatically applied with a visual indicator showing it's been overridden. A "Reset to Auto" button in the power selector restores the auto-detected power for your device model. ### Improvements - Redesigned the Top Heard overlay. Now shows the repeaters that heard your most recent ping sorted by SNR, with color-coded indicators per ping type (green for TX, purple for Discovery, cyan for Trace, blue for RX). Top 3 slots show the best results from your latest ping and fully replace on each new ping. RX slot now shows the strongest passively overheard repeater within a rolling window that matches your auto-ping interval (15s, 30s, or 60s) instead of a hardcoded 5 seconds. Overlay clears on auto-ping stop, mode switch, disconnect, or log clear. --- .build_version | 2 +- lib/providers/app_state_provider.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.build_version b/.build_version index 26aaba0..6085e94 100644 --- a/.build_version +++ b/.build_version @@ -1 +1 @@ -1.2.0 +1.2.1 diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart index 745b96f..e090f55 100644 --- a/lib/providers/app_state_provider.dart +++ b/lib/providers/app_state_provider.dart @@ -379,7 +379,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { _topRepeatersOverlay = fresh.take(3).toList(); } - /// Update the RX overlay slot with a 5-second rolling window (best SNR wins). + /// Update the RX overlay slot — window matches auto-ping interval (best SNR wins). void _updateRxOverlaySlot(String repeaterId, double snr) { final entry = (repeaterId: repeaterId.toUpperCase(), snr: snr); if (_rxOverlayWindowTimer?.isActive ?? false) { @@ -388,7 +388,7 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver { } } else { _rxOverlaySlot = entry; - _rxOverlayWindowTimer = Timer(const Duration(seconds: 5), () { + _rxOverlayWindowTimer = Timer(Duration(seconds: _preferences.autoPingInterval), () { // Window closed — slot stays until next RX or cleared }); }