mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-12 08:50:30 +00:00
Refactor code for improved readability and consistency across multiple files
- Updated formatting in `drawing_toolbar.dart` for better readability, including breaking long lines and ensuring consistent indentation. - Enhanced the `recipient_selector_sheet.dart` by adjusting line breaks and improving the layout of text styles. - Refactored `sar_update_sheet.dart` to improve readability, including restructuring widget layouts and ensuring consistent formatting. - Cleaned up imports and removed unnecessary lines in `widget_test.dart`.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
/// Type of response expected from a command
|
||||
@@ -95,7 +94,8 @@ class BleCommandQueue {
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
// Determine timeout based on response type
|
||||
final cmdTimeout = timeout ??
|
||||
final cmdTimeout =
|
||||
timeout ??
|
||||
(responseType == CommandResponseType.data
|
||||
? const Duration(seconds: 10)
|
||||
: const Duration(seconds: 5));
|
||||
@@ -114,7 +114,9 @@ class BleCommandQueue {
|
||||
_queue.add(command);
|
||||
onQueueSizeChanged?.call(_queue.length);
|
||||
|
||||
debugPrint('📋 [CommandQueue] Enqueued command 0x${commandCode.toRadixString(16).padLeft(2, '0')} (queue size: ${_queue.length})');
|
||||
debugPrint(
|
||||
'📋 [CommandQueue] Enqueued command 0x${commandCode.toRadixString(16).padLeft(2, '0')} (queue size: ${_queue.length})',
|
||||
);
|
||||
|
||||
// Start processing if not already running
|
||||
if (!_isProcessing) {
|
||||
@@ -125,9 +127,13 @@ class BleCommandQueue {
|
||||
return command.completer.future.timeout(
|
||||
cmdTimeout,
|
||||
onTimeout: () {
|
||||
debugPrint('⏱️ [CommandQueue] Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} timed out after ${cmdTimeout.inSeconds}s');
|
||||
debugPrint(
|
||||
'⏱️ [CommandQueue] Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} timed out after ${cmdTimeout.inSeconds}s',
|
||||
);
|
||||
_pendingResponses.remove(commandCode);
|
||||
throw TimeoutException('Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} timed out');
|
||||
throw TimeoutException(
|
||||
'Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} timed out',
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -152,7 +158,9 @@ class BleCommandQueue {
|
||||
final remainingDelay = _minDelayMs - elapsed.inMilliseconds;
|
||||
|
||||
if (remainingDelay > 0) {
|
||||
debugPrint('⏸️ [CommandQueue] Waiting ${remainingDelay}ms before next command');
|
||||
debugPrint(
|
||||
'⏸️ [CommandQueue] Waiting ${remainingDelay}ms before next command',
|
||||
);
|
||||
await Future.delayed(Duration(milliseconds: remainingDelay));
|
||||
}
|
||||
}
|
||||
@@ -170,7 +178,9 @@ class BleCommandQueue {
|
||||
|
||||
// Execute command (handled by BleCommandSender)
|
||||
// The completer will be completed by completeCommand() when response arrives
|
||||
debugPrint('📤 [CommandQueue] Executing command 0x${command.commandCode.toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(
|
||||
'📤 [CommandQueue] Executing command 0x${command.commandCode.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
|
||||
// For fire-and-forget commands, complete immediately
|
||||
if (command.responseType == CommandResponseType.none) {
|
||||
@@ -209,7 +219,9 @@ class BleCommandQueue {
|
||||
void completeCommand<T>(int responseCode, T data) {
|
||||
final command = _pendingResponses.remove(responseCode);
|
||||
if (command != null) {
|
||||
debugPrint('✅ [CommandQueue] Completing command 0x${command.commandCode.toRadixString(16).padLeft(2, '0')} with response 0x${responseCode.toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(
|
||||
'✅ [CommandQueue] Completing command 0x${command.commandCode.toRadixString(16).padLeft(2, '0')} with response 0x${responseCode.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
if (!command.completer.isCompleted) {
|
||||
command.completer.complete(data);
|
||||
}
|
||||
@@ -219,10 +231,16 @@ class BleCommandQueue {
|
||||
/// Complete a pending command with error
|
||||
///
|
||||
/// Called by BleResponseHandler when RESP_CODE_ERR is received
|
||||
void completeCommandWithError(int commandCode, String error, {int? errorCode}) {
|
||||
void completeCommandWithError(
|
||||
int commandCode,
|
||||
String error, {
|
||||
int? errorCode,
|
||||
}) {
|
||||
final command = _pendingResponses.remove(commandCode);
|
||||
if (command != null) {
|
||||
debugPrint('❌ [CommandQueue] Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} failed: $error (code: $errorCode)');
|
||||
debugPrint(
|
||||
'❌ [CommandQueue] Command 0x${commandCode.toRadixString(16).padLeft(2, '0')} failed: $error (code: $errorCode)',
|
||||
);
|
||||
if (!command.completer.isCompleted) {
|
||||
command.completer.completeError(
|
||||
Exception('Command failed: $error (error code: $errorCode)'),
|
||||
@@ -245,7 +263,9 @@ class BleCommandQueue {
|
||||
|
||||
/// Clear all pending commands (use with caution)
|
||||
void clear() {
|
||||
debugPrint('🗑️ [CommandQueue] Clearing queue (${_queue.length} commands, ${_pendingResponses.length} pending responses)');
|
||||
debugPrint(
|
||||
'🗑️ [CommandQueue] Clearing queue (${_queue.length} commands, ${_pendingResponses.length} pending responses)',
|
||||
);
|
||||
|
||||
// Complete all pending commands with error
|
||||
for (final command in _pendingResponses.values) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import '../meshcore_opcode_names.dart';
|
||||
@@ -130,10 +129,13 @@ class BleCommandSender {
|
||||
|
||||
debugPrint('📤 [TX] Sending command: $opcodeName ($opcodeHex)');
|
||||
debugPrint(' Data size: ${data.length} bytes');
|
||||
debugPrint(' Hex: ${data.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}');
|
||||
debugPrint(
|
||||
' Hex: ${data.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}',
|
||||
);
|
||||
|
||||
// Check if the characteristic supports write without response
|
||||
final supportsWriteWithoutResponse = _rxCharacteristic!.properties.writeWithoutResponse;
|
||||
final supportsWriteWithoutResponse =
|
||||
_rxCharacteristic!.properties.writeWithoutResponse;
|
||||
final supportsWrite = _rxCharacteristic!.properties.write;
|
||||
|
||||
if (supportsWriteWithoutResponse) {
|
||||
@@ -160,15 +162,21 @@ class BleCommandSender {
|
||||
}
|
||||
|
||||
/// Log a packet
|
||||
void _logPacket(Uint8List data, PacketDirection direction, {int? responseCode}) {
|
||||
void _logPacket(
|
||||
Uint8List data,
|
||||
PacketDirection direction, {
|
||||
int? responseCode,
|
||||
}) {
|
||||
// Add new packet
|
||||
_packetLogs.add(BlePacketLog(
|
||||
timestamp: DateTime.now(),
|
||||
rawData: data,
|
||||
direction: direction,
|
||||
responseCode: responseCode,
|
||||
description: _getPacketDescription(responseCode),
|
||||
));
|
||||
_packetLogs.add(
|
||||
BlePacketLog(
|
||||
timestamp: DateTime.now(),
|
||||
rawData: data,
|
||||
direction: direction,
|
||||
responseCode: responseCode,
|
||||
description: _getPacketDescription(responseCode),
|
||||
),
|
||||
);
|
||||
|
||||
// Limit log size to prevent memory issues
|
||||
if (_packetLogs.length > _maxLogSize) {
|
||||
|
||||
@@ -17,24 +17,38 @@ import 'ble_command_queue.dart';
|
||||
typedef OnContactCallback = void Function(Contact contact);
|
||||
typedef OnContactsCompleteCallback = void Function(List<Contact> contacts);
|
||||
typedef OnMessageCallback = void Function(Message message);
|
||||
typedef OnTelemetryCallback = void Function(Uint8List publicKey, Uint8List lppData);
|
||||
typedef OnTelemetryCallback =
|
||||
void Function(Uint8List publicKey, Uint8List lppData);
|
||||
typedef OnSelfInfoCallback = void Function(Map<String, dynamic> selfInfo);
|
||||
typedef OnDeviceInfoCallback = void Function(Map<String, dynamic> deviceInfo);
|
||||
typedef OnNoMoreMessagesCallback = void Function();
|
||||
typedef OnMessageWaitingCallback = void Function();
|
||||
typedef OnLoginSuccessCallback = void Function(Uint8List publicKeyPrefix, int permissions, bool isAdmin, int tag);
|
||||
typedef OnLoginSuccessCallback =
|
||||
void Function(
|
||||
Uint8List publicKeyPrefix,
|
||||
int permissions,
|
||||
bool isAdmin,
|
||||
int tag,
|
||||
);
|
||||
typedef OnLoginFailCallback = void Function(Uint8List publicKeyPrefix);
|
||||
typedef OnAdvertReceivedCallback = void Function(Uint8List publicKey);
|
||||
typedef OnPathUpdatedCallback = void Function(Uint8List publicKey);
|
||||
typedef OnMessageSentCallback = void Function(int expectedAckTag, int suggestedTimeoutMs, bool isFloodMode);
|
||||
typedef OnMessageDeliveredCallback = void Function(int ackCode, int roundTripTimeMs);
|
||||
typedef OnStatusResponseCallback = void Function(Uint8List publicKeyPrefix, Uint8List statusData);
|
||||
typedef OnBinaryResponseCallback = void Function(Uint8List publicKeyPrefix, int tag, Uint8List responseData);
|
||||
typedef OnBatteryAndStorageCallback = void Function(int millivolts, int? usedKb, int? totalKb);
|
||||
typedef OnMessageSentCallback =
|
||||
void Function(int expectedAckTag, int suggestedTimeoutMs, bool isFloodMode);
|
||||
typedef OnMessageDeliveredCallback =
|
||||
void Function(int ackCode, int roundTripTimeMs);
|
||||
typedef OnStatusResponseCallback =
|
||||
void Function(Uint8List publicKeyPrefix, Uint8List statusData);
|
||||
typedef OnBinaryResponseCallback =
|
||||
void Function(Uint8List publicKeyPrefix, int tag, Uint8List responseData);
|
||||
typedef OnBatteryAndStorageCallback =
|
||||
void Function(int millivolts, int? usedKb, int? totalKb);
|
||||
typedef OnErrorCallback = void Function(String error, {int? errorCode});
|
||||
typedef OnContactNotFoundCallback = void Function(Uint8List? contactPublicKey);
|
||||
typedef OnChannelInfoCallback = void Function(int channelIdx, String channelName);
|
||||
typedef OnMessageEchoDetectedCallback = void Function(String messageId, int echoCount, int snrRaw, int rssiDbm);
|
||||
typedef OnChannelInfoCallback =
|
||||
void Function(int channelIdx, String channelName);
|
||||
typedef OnMessageEchoDetectedCallback =
|
||||
void Function(String messageId, int echoCount, int snrRaw, int rssiDbm);
|
||||
|
||||
/// Processes incoming responses from the BLE device
|
||||
class BleResponseHandler {
|
||||
@@ -118,12 +132,18 @@ class BleResponseHandler {
|
||||
final responseCode = reader.readByte();
|
||||
|
||||
// Get opcode name for logging
|
||||
final opcodeName = MeshCoreOpcodeNames.getOpcodeName(responseCode, isTx: false);
|
||||
final opcodeHex = '0x${responseCode.toRadixString(16).padLeft(2, '0').toUpperCase()}';
|
||||
final opcodeName = MeshCoreOpcodeNames.getOpcodeName(
|
||||
responseCode,
|
||||
isTx: false,
|
||||
);
|
||||
final opcodeHex =
|
||||
'0x${responseCode.toRadixString(16).padLeft(2, '0').toUpperCase()}';
|
||||
|
||||
debugPrint('📥 [RX] Received: $opcodeName ($opcodeHex)');
|
||||
debugPrint(' Data size: ${data.length} bytes');
|
||||
debugPrint(' Hex: ${data.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}');
|
||||
debugPrint(
|
||||
' Hex: ${data.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}',
|
||||
);
|
||||
debugPrint(' Payload: ${reader.remainingBytesCount} bytes');
|
||||
|
||||
// Log RX packet (before processing so we capture everything)
|
||||
@@ -254,7 +274,9 @@ class BleResponseHandler {
|
||||
try {
|
||||
final contact = FrameParser.parseContact(reader);
|
||||
debugPrint(' ✅ [Contact] Parsed successfully: ${contact.advName}');
|
||||
debugPrint(' outPathLen: ${contact.outPathLen} (${contact.pathDescription})');
|
||||
debugPrint(
|
||||
' outPathLen: ${contact.outPathLen} (${contact.pathDescription})',
|
||||
);
|
||||
_pendingContacts.add(contact);
|
||||
onContactReceived?.call(contact);
|
||||
} catch (e) {
|
||||
@@ -416,7 +438,9 @@ class BleResponseHandler {
|
||||
/// Handle LogRxData push - includes extensive decoding logic
|
||||
void _handleLogRxData(BufferReader reader) {
|
||||
try {
|
||||
debugPrint(' [LogRxData] Parsing log rx data from over-the-air packet...');
|
||||
debugPrint(
|
||||
' [LogRxData] Parsing log rx data from over-the-air packet...',
|
||||
);
|
||||
final data = reader.readRemainingBytes();
|
||||
|
||||
if (data.length < 2) {
|
||||
@@ -445,25 +469,35 @@ class BleResponseHandler {
|
||||
final payloadType = (header >> 2) & 0x0F;
|
||||
final pathLen = rawPacketData[1];
|
||||
|
||||
debugPrint(' Packet type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(
|
||||
' Packet type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
|
||||
if (pathLen > 0 && rawPacketData.length >= 2 + pathLen) {
|
||||
final path = rawPacketData.sublist(2, 2 + pathLen);
|
||||
final pathStr = path.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' → ');
|
||||
final pathStr = path
|
||||
.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}')
|
||||
.join(' → ');
|
||||
debugPrint(' Path ($pathLen hops): $pathStr');
|
||||
|
||||
// Highlight multi-hop packets
|
||||
if (pathLen > 1) {
|
||||
debugPrint(' 🔄 MULTI-HOP PACKET! Original sender: 0x${path[0].toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(
|
||||
' 🔄 MULTI-HOP PACKET! Original sender: 0x${path[0].toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
}
|
||||
|
||||
// Check if our node hash is in the path
|
||||
if (_ourNodeHash != null && path.contains(_ourNodeHash!)) {
|
||||
debugPrint(' ✅✅✅ ECHO DETECTED! Path contains our hash (0x${_ourNodeHash!.toRadixString(16).padLeft(2, '0')}) ✅✅✅');
|
||||
debugPrint(
|
||||
' ✅✅✅ ECHO DETECTED! Path contains our hash (0x${_ourNodeHash!.toRadixString(16).padLeft(2, '0')}) ✅✅✅',
|
||||
);
|
||||
if (path[0] == _ourNodeHash) {
|
||||
debugPrint(' 👉 WE are the original sender!');
|
||||
} else {
|
||||
debugPrint(' 👉 Original sender: 0x${path[0].toRadixString(16).padLeft(2, '0')}, WE sent it to the network');
|
||||
debugPrint(
|
||||
' 👉 Original sender: 0x${path[0].toRadixString(16).padLeft(2, '0')}, WE sent it to the network',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
debugPrint(' ℹ️ Does NOT contain our hash (not our message)');
|
||||
@@ -526,7 +560,11 @@ class BleResponseHandler {
|
||||
hash = hash & 0xFFFFFFFF; // Keep 32-bit
|
||||
}
|
||||
if (packet.length > 16) {
|
||||
for (int i = packet.length ~/ 2; i < packet.length ~/ 2 + 8 && i < packet.length; i++) {
|
||||
for (
|
||||
int i = packet.length ~/ 2;
|
||||
i < packet.length ~/ 2 + 8 && i < packet.length;
|
||||
i++
|
||||
) {
|
||||
hash = ((hash << 5) - hash) + packet[i];
|
||||
hash = hash & 0xFFFFFFFF;
|
||||
}
|
||||
@@ -543,7 +581,9 @@ class BleResponseHandler {
|
||||
/// Check if received packet is an echo of a sent message
|
||||
void _checkForEcho(Uint8List rawPacket, int snrRaw, int rssiDbm) {
|
||||
try {
|
||||
debugPrint(' 🔍 [Echo] _checkForEcho called, packet size: ${rawPacket.length} bytes');
|
||||
debugPrint(
|
||||
' 🔍 [Echo] _checkForEcho called, packet size: ${rawPacket.length} bytes',
|
||||
);
|
||||
|
||||
// Need at least header + path_len
|
||||
if (rawPacket.length < 2) {
|
||||
@@ -553,7 +593,9 @@ class BleResponseHandler {
|
||||
|
||||
final header = rawPacket[0];
|
||||
final payloadType = (header >> 2) & 0x0F;
|
||||
debugPrint(' 🔍 [Echo] Payload type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(
|
||||
' 🔍 [Echo] Payload type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
if (payloadType != 0x05) {
|
||||
debugPrint(' ⚠️ [Echo] Not GRP_TXT, ignoring');
|
||||
return; // Only track GRP_TXT
|
||||
@@ -568,10 +610,13 @@ class BleResponseHandler {
|
||||
|
||||
// Extract path for unique echo tracking
|
||||
final path = rawPacket.sublist(2, 2 + pathLen);
|
||||
final pathSignature = path.map((b) => b.toRadixString(16).padLeft(2, '0')).join(':');
|
||||
final pathSignature = path
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
|
||||
// Check if our node hash is in the path (meaning this is our message being rebroadcast)
|
||||
final containsOurHash = _ourNodeHash != null && path.contains(_ourNodeHash!);
|
||||
final containsOurHash =
|
||||
_ourNodeHash != null && path.contains(_ourNodeHash!);
|
||||
if (!containsOurHash) {
|
||||
// This packet doesn't have our hash in the path, so it's not our message
|
||||
return;
|
||||
@@ -599,9 +644,16 @@ class BleResponseHandler {
|
||||
debugPrint(' Unique paths: ${tracker.uniqueEchoPaths.length}');
|
||||
|
||||
// Notify callback
|
||||
onMessageEchoDetected?.call(tracker.messageId, tracker.echoCount, snrRaw, rssiDbm);
|
||||
onMessageEchoDetected?.call(
|
||||
tracker.messageId,
|
||||
tracker.echoCount,
|
||||
snrRaw,
|
||||
rssiDbm,
|
||||
);
|
||||
} else {
|
||||
debugPrint(' ♻️ [Echo] Duplicate path (already counted): $pathSignature');
|
||||
debugPrint(
|
||||
' ♻️ [Echo] Duplicate path (already counted): $pathSignature',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,7 +683,9 @@ class BleResponseHandler {
|
||||
|
||||
// Store by message ID temporarily
|
||||
_sentMessageTrackers[messageId] = tracker;
|
||||
debugPrint(' 📤 [Echo] Tracking message $messageId (will match any GRP_TXT within 10000ms)');
|
||||
debugPrint(
|
||||
' 📤 [Echo] Tracking message $messageId (will match any GRP_TXT within 10000ms)',
|
||||
);
|
||||
debugPrint(' 📊 [Echo] Total trackers: ${_sentMessageTrackers.length}');
|
||||
|
||||
// Cleanup if too many trackers
|
||||
@@ -649,8 +703,12 @@ class BleResponseHandler {
|
||||
/// Set our node hash for packet identification
|
||||
void setOurNodeHash(int nodeHash) {
|
||||
_ourNodeHash = nodeHash;
|
||||
debugPrint(' 🔑 [Echo] Our node hash set to: 0x${nodeHash.toRadixString(16).padLeft(2, '0')}');
|
||||
debugPrint(' ℹ️ [Echo] Will track packets containing our hash in the path');
|
||||
debugPrint(
|
||||
' 🔑 [Echo] Our node hash set to: 0x${nodeHash.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
debugPrint(
|
||||
' ℹ️ [Echo] Will track packets containing our hash in the path',
|
||||
);
|
||||
}
|
||||
|
||||
/// Associate a captured packet with a sent message
|
||||
@@ -666,7 +724,9 @@ class BleResponseHandler {
|
||||
/// [3+] = rest of path + encrypted payload
|
||||
void _associatePacketWithSentMessage(Uint8List rawPacket) {
|
||||
try {
|
||||
debugPrint(' 🔍 [Echo] _associatePacketWithSentMessage called, packet size: ${rawPacket.length}');
|
||||
debugPrint(
|
||||
' 🔍 [Echo] _associatePacketWithSentMessage called, packet size: ${rawPacket.length}',
|
||||
);
|
||||
|
||||
// Need at least 3 bytes: header + path_len + first path byte
|
||||
if (rawPacket.length < 3) {
|
||||
@@ -677,8 +737,11 @@ class BleResponseHandler {
|
||||
// Check if this is a GRP_TXT packet (payload type = 0x05)
|
||||
final header = rawPacket[0];
|
||||
final payloadType = (header >> 2) & 0x0F;
|
||||
debugPrint(' 🔍 [Echo] Association check - Payload type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}');
|
||||
if (payloadType != 0x05) { // Not a group message
|
||||
debugPrint(
|
||||
' 🔍 [Echo] Association check - Payload type: 0x${payloadType.toRadixString(16).padLeft(2, '0')}',
|
||||
);
|
||||
if (payloadType != 0x05) {
|
||||
// Not a group message
|
||||
debugPrint(' ⚠️ [Echo] Not GRP_TXT, skipping association');
|
||||
return;
|
||||
}
|
||||
@@ -694,16 +757,21 @@ class BleResponseHandler {
|
||||
|
||||
// Extract the path from the packet for unique echo tracking
|
||||
final path = rawPacket.sublist(2, 2 + pathLen);
|
||||
final pathSignature = path.map((b) => b.toRadixString(16).padLeft(2, '0')).join(':');
|
||||
final pathSignature = path
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
|
||||
// Check if our node hash is in the path (meaning this is our message being rebroadcast)
|
||||
final containsOurHash = _ourNodeHash != null && path.contains(_ourNodeHash!);
|
||||
final containsOurHash =
|
||||
_ourNodeHash != null && path.contains(_ourNodeHash!);
|
||||
if (!containsOurHash) {
|
||||
// This packet doesn't have our hash in the path, so it's not our message
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint(' ✅ [Echo] Packet contains our hash (0x${_ourNodeHash!.toRadixString(16).padLeft(2, '0')}) in path: $pathSignature');
|
||||
debugPrint(
|
||||
' ✅ [Echo] Packet contains our hash (0x${_ourNodeHash!.toRadixString(16).padLeft(2, '0')}) in path: $pathSignature',
|
||||
);
|
||||
|
||||
// Extract encrypted payload (everything after path)
|
||||
final payloadStart = 2 + pathLen;
|
||||
@@ -754,13 +822,17 @@ class BleResponseHandler {
|
||||
|
||||
/// Remove expired trackers
|
||||
void _cleanupExpiredTrackers() {
|
||||
final expiredCount = _sentMessageTrackers.values.where((t) => t.isExpired).length;
|
||||
final expiredCount = _sentMessageTrackers.values
|
||||
.where((t) => t.isExpired)
|
||||
.length;
|
||||
if (expiredCount > 0) {
|
||||
debugPrint(' 🧹 [Echo] Cleaning up $expiredCount expired tracker(s)');
|
||||
}
|
||||
_sentMessageTrackers.removeWhere((key, tracker) {
|
||||
if (tracker.isExpired && tracker.packetHashHex == 'pending') {
|
||||
debugPrint(' ⏱️ [Echo] Tracker expired without capturing: ${tracker.messageId}');
|
||||
debugPrint(
|
||||
' ⏱️ [Echo] Tracker expired without capturing: ${tracker.messageId}',
|
||||
);
|
||||
}
|
||||
return tracker.isExpired;
|
||||
});
|
||||
@@ -774,7 +846,9 @@ class BleResponseHandler {
|
||||
final sortedEntries = _sentMessageTrackers.entries.toList()
|
||||
..sort((a, b) => a.value.sentTime.compareTo(b.value.sentTime));
|
||||
|
||||
final toRemove = sortedEntries.take(_sentMessageTrackers.length - _maxTrackers);
|
||||
final toRemove = sortedEntries.take(
|
||||
_sentMessageTrackers.length - _maxTrackers,
|
||||
);
|
||||
for (final entry in toRemove) {
|
||||
_sentMessageTrackers.remove(entry.key);
|
||||
}
|
||||
@@ -787,7 +861,9 @@ class BleResponseHandler {
|
||||
try {
|
||||
final contact = FrameParser.parseContact(reader);
|
||||
debugPrint(' ✅ [NewAdvert] Parsed successfully: ${contact.advName}');
|
||||
debugPrint(' outPathLen: ${contact.outPathLen} (${contact.pathDescription})');
|
||||
debugPrint(
|
||||
' outPathLen: ${contact.outPathLen} (${contact.pathDescription})',
|
||||
);
|
||||
onContactReceived?.call(contact);
|
||||
} catch (e) {
|
||||
debugPrint(' ❌ [NewAdvert] Parsing error: $e');
|
||||
@@ -937,7 +1013,7 @@ class BleResponseHandler {
|
||||
final channelIdx = info['channelIdx'] as int;
|
||||
final channelName = info['channelName'] as String;
|
||||
|
||||
debugPrint(' ✅ [ChannelInfo] Channel $channelIdx: "${channelName}"');
|
||||
debugPrint(' ✅ [ChannelInfo] Channel $channelIdx: "$channelName"');
|
||||
onChannelInfoReceived?.call(channelIdx, channelName);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -956,14 +1032,17 @@ class BleResponseHandler {
|
||||
|
||||
// Complete any pending ACK command with error
|
||||
_commandQueue?.completeCommandWithError(
|
||||
MeshCoreConstants.respOk, // Command was expecting OK, got ERR
|
||||
MeshCoreConstants.respOk, // Command was expecting OK, got ERR
|
||||
errorMsg,
|
||||
errorCode: errorCode,
|
||||
);
|
||||
|
||||
// Special handling for ERR_CODE_NOT_FOUND (2) - contact not in radio
|
||||
if (errorCode == 2) { // ERR_CODE_NOT_FOUND
|
||||
debugPrint(' ⚠️ [Error] Contact not found in radio - attempting auto-recovery');
|
||||
if (errorCode == 2) {
|
||||
// ERR_CODE_NOT_FOUND
|
||||
debugPrint(
|
||||
' ⚠️ [Error] Contact not found in radio - attempting auto-recovery',
|
||||
);
|
||||
onContactNotFound?.call(_lastContactPublicKey);
|
||||
}
|
||||
|
||||
@@ -980,14 +1059,20 @@ class BleResponseHandler {
|
||||
}
|
||||
|
||||
/// Log a packet
|
||||
void _logPacket(Uint8List data, PacketDirection direction, {int? responseCode}) {
|
||||
_packetLogs.add(BlePacketLog(
|
||||
timestamp: DateTime.now(),
|
||||
rawData: data,
|
||||
direction: direction,
|
||||
responseCode: responseCode,
|
||||
description: _getPacketDescription(responseCode),
|
||||
));
|
||||
void _logPacket(
|
||||
Uint8List data,
|
||||
PacketDirection direction, {
|
||||
int? responseCode,
|
||||
}) {
|
||||
_packetLogs.add(
|
||||
BlePacketLog(
|
||||
timestamp: DateTime.now(),
|
||||
rawData: data,
|
||||
direction: direction,
|
||||
responseCode: responseCode,
|
||||
description: _getPacketDescription(responseCode),
|
||||
),
|
||||
);
|
||||
|
||||
if (_packetLogs.length > _maxLogSize) {
|
||||
_packetLogs.removeAt(0);
|
||||
|
||||
Reference in New Issue
Block a user