meshcore-open/lib/widgets/debug_frame_viewer.dart
Winston Lowe dbefb0b5f4 feat: Enhance MeshCoreConnector with storage metrics and improve error handling
- Added storageUsedKb and storageTotalKb properties to MeshCoreConnector.
- Updated battery and storage frame parsing with improved error handling.
- Refactored log RX data handling to use BufferReader for better readability and error management.
- Enhanced message parsing in ChannelMessage and Message classes to utilize BufferReader.
- Introduced new text type for signed messages in meshcore_protocol.dart.
- Updated BLE debug log screen to use BufferReader for payload parsing.
- Refactored message retry service to handle ACK hashes as integers instead of Uint8List.
- Improved message storage serialization and deserialization to accommodate new expectedAckHash type.
- Added wasPulled property to Contact model for better state management.
2026-03-21 13:01:02 -07:00

100 lines
3 KiB
Dart

import 'dart:typed_data';
import 'package:flutter/material.dart';
import '../l10n/l10n.dart';
import '../connector/meshcore_protocol.dart';
/// Debug widget to show the hex dump of a frame
class DebugFrameViewer {
static void showFrameDebug(
BuildContext context,
Uint8List frame,
String title,
) {
// Helper to read uint32 little-endian
int readUint32LE(Uint8List data, int offset) {
return data[offset] |
(data[offset + 1] << 8) |
(data[offset + 2] << 16) |
(data[offset + 3] << 24);
}
final hexString = frame
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join(' ');
final details = StringBuffer();
details.writeln(context.l10n.debugFrame_length(frame.length));
details.writeln('');
details.writeln(
context.l10n.debugFrame_command(
frame[0].toRadixString(16).padLeft(2, '0'),
),
);
if (frame[0] == cmdSendTxtMsg && frame.length > 37) {
details.writeln('');
details.writeln(context.l10n.debugFrame_textMessageHeader);
details.writeln(
context.l10n.debugFrame_destinationPubKey(
pubKeyToHex(frame.sublist(1, 33)),
),
);
details.writeln(
context.l10n.debugFrame_timestamp(readUint32LE(frame, 33)),
);
details.writeln(
context.l10n.debugFrame_flags(
frame[37].toRadixString(16).padLeft(2, '0'),
),
);
final txtType = (frame[37] >> 2) & 0x03;
final typeLabel = txtType == txtTypeCliData
? context.l10n.debugFrame_textTypeCli
: context.l10n.debugFrame_textTypePlain;
details.writeln(context.l10n.debugFrame_textType(txtType, typeLabel));
if (frame.length > 38) {
final textBytes = frame.sublist(38);
final nullIdx = textBytes.indexOf(0);
final text = String.fromCharCodes(
nullIdx >= 0 ? textBytes.sublist(0, nullIdx) : textBytes,
);
details.writeln(context.l10n.debugFrame_text(text));
}
}
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
details.toString(),
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
const Divider(),
Text(
context.l10n.debugFrame_hexDump,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
hexString,
style: const TextStyle(fontFamily: 'monospace', fontSize: 11),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(context.l10n.common_close),
),
],
),
);
}
}