feat: Add Packet Log Screen for BLE packet logging and exporting

- Implemented PacketLogScreen to display and filter BLE packet logs.
- Added functionality to export logs as CSV and text files.
- Introduced clipboard copy feature for hex data.
- Implemented clear logs functionality with confirmation dialog.
- Enhanced MeshCoreBleService to log TX and RX packets with descriptions.
- Added BufferReader methods for reading unsigned and signed 16-bit integers (big-endian).
- Updated CayenneLppParser to read values as big-endian.
- Created MessageStorageService for persisting messages to local storage.
- Enhanced map markers to display telemetry data including voltage, humidity, and pressure.
This commit is contained in:
Janez T
2025-10-14 15:27:18 +02:00
parent ccec842672
commit 59de627289
20 changed files with 4960 additions and 153 deletions

View File

@@ -41,6 +41,9 @@ class ConnectionProvider with ChangeNotifier {
int get rxPacketCount => _bleService.rxPacketCount;
int get txPacketCount => _bleService.txPacketCount;
// Message sync state
bool _noMoreMessages = false;
// Callbacks for other providers
Function(Contact)? onContactReceived;
Function(List<Contact>)? onContactsComplete;
@@ -104,6 +107,11 @@ class ConnectionProvider with ChangeNotifier {
onTelemetryReceived?.call(publicKey, lppData);
};
_bleService.onNoMoreMessages = () {
print('📥 [Provider] Received NoMoreMessages signal');
_noMoreMessages = true;
};
_bleService.onSelfInfoReceived = (selfInfo) {
print('📥 [Provider] Received SelfInfo:');
print(' TX Power: ${selfInfo['txPower']} / ${selfInfo['maxTxPower']} dBm');
@@ -297,7 +305,8 @@ class ConnectionProvider with ChangeNotifier {
}
/// Request telemetry from contact
Future<void> requestTelemetry(Uint8List contactPublicKey) async {
/// [zeroHop] - if true, only direct connection (no mesh forwarding)
Future<void> requestTelemetry(Uint8List contactPublicKey, {bool zeroHop = false}) async {
if (!_bleService.isConnected) {
_error = 'Not connected to device';
notifyListeners();
@@ -305,7 +314,7 @@ class ConnectionProvider with ChangeNotifier {
}
try {
await _bleService.requestTelemetry(contactPublicKey);
await _bleService.requestTelemetry(contactPublicKey, zeroHop: zeroHop);
} catch (e) {
_error = 'Failed to request telemetry: $e';
notifyListeners();
@@ -421,6 +430,66 @@ class ConnectionProvider with ChangeNotifier {
}
}
/// Sync messages from device queue
/// Call this repeatedly until no more messages are available
Future<bool> syncNextMessage() async {
if (!_bleService.isConnected) {
_error = 'Not connected to device';
notifyListeners();
return false;
}
try {
await _bleService.syncNextMessage();
return true;
} catch (e) {
_error = 'Failed to sync message: $e';
notifyListeners();
return false;
}
}
/// Sync all waiting messages from device
Future<int> syncAllMessages() async {
if (!_bleService.isConnected) {
_error = 'Not connected to device';
notifyListeners();
return 0;
}
int count = 0;
_noMoreMessages = false; // Reset flag
try {
print('🔄 [Provider] Starting message sync...');
// Keep syncing until we get NoMoreMessages response
// The device will send ContactMsgRecv or ChannelMsgRecv responses
// until it sends NoMoreMessages
for (int i = 0; i < 100; i++) { // Safety limit
if (_noMoreMessages) {
print('✅ [Provider] Message sync complete - NoMoreMessages received after $count requests');
break;
}
await _bleService.syncNextMessage();
count++;
// Small delay to allow response to be processed
await Future.delayed(const Duration(milliseconds: 100));
}
if (!_noMoreMessages && count >= 100) {
print('⚠️ [Provider] Message sync stopped - reached safety limit of 100 requests');
}
return count;
} catch (e) {
_error = 'Failed to sync messages: $e';
notifyListeners();
return count;
}
}
/// Clear error message
void clearError() {
_error = null;