diff --git a/lib/connector/caplog_reassembler.dart b/lib/connector/caplog_reassembler.dart index 6f796af..6d9ed25 100644 --- a/lib/connector/caplog_reassembler.dart +++ b/lib/connector/caplog_reassembler.dart @@ -77,10 +77,17 @@ class CaplogTruncatedException implements Exception { const CaplogTruncatedException({ required this.received, required this.expected, + this.chunks, }); final int received; final int expected; + + /// Number of CHUNK frames the client accumulated before END — a diagnostic to + /// tell client/transport frame loss apart from the firmware streaming short. + final int? chunks; + @override String toString() => - 'CaplogTruncatedException: received $received of $expected bytes'; + 'CaplogTruncatedException: received $received of $expected bytes' + '${chunks != null ? ' in $chunks chunks' : ''}'; } diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index 784ddc3..6db865b 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -290,6 +290,7 @@ class MeshCoreConnector extends ChangeNotifier { bool _caplogAwaitingStart = false; Completer? _caplogAckCompleter; Completer? _caplogStatusCompleter; + int _caplogChunks = 0; // CHUNK frames in the active download (diagnostic) String? _firmwareVersion; String? _deviceModel; int? _offbandCaps; @@ -4354,10 +4355,15 @@ class MeshCoreConnector extends ChangeNotifier { switch (event.status) { case CaplogStatus.started: _caplogAwaitingStart = false; + _caplogChunks = 0; + break; + case CaplogStatus.chunk: + _caplogChunks++; break; case CaplogStatus.completed: _appDebugLogService?.info( - 'Caplog download complete: ${event.bytes!.length} bytes', + 'Caplog download complete: ${event.bytes!.length} bytes in ' + '$_caplogChunks chunks', tag: 'Caplog', ); completer.complete(event.bytes); @@ -4365,17 +4371,17 @@ class MeshCoreConnector extends ChangeNotifier { case CaplogStatus.truncated: _appDebugLogService?.warn( 'Caplog download truncated: ${event.bytes!.length} of ' - '${event.expected} bytes', + '${event.expected} bytes in $_caplogChunks chunks', tag: 'Caplog', ); completer.completeError( CaplogTruncatedException( received: event.bytes!.length, expected: event.expected!, + chunks: _caplogChunks, ), ); break; - case CaplogStatus.chunk: case CaplogStatus.ignored: break; }