Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions lib/src/control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,12 @@ ConsoleLogChunk? parseConsoleLog(Uint8List inner) {
/// run has accumulated so far. A gap in `record_index` (a dropped/reordered
/// frame) flushes what's buffered rather than silently splicing unrelated
/// text together.
///
/// Check [hasCompletedRun] before calling [flush] — don't react to [add]'s
/// raw boolean. `add()` returning false means "not contiguous with the last
/// chunk", which is also true for the very first chunk into a fresh or
/// just-flushed instance; flushing on every `false` would hand back that lone
/// chunk instead of letting the run keep building.
class ConsoleLogReassembler {
final StringBuffer _buf = StringBuffer();

Expand All @@ -1247,9 +1253,14 @@ class ConsoleLogReassembler {
String? _completed;
int? _lastIndex;

/// True when a gap has parked a finished run for [flush] to return. Use
/// this, not [add]'s return value, to decide whether to call [flush].
bool get hasCompletedRun => _completed != null;

/// Feed one decoded chunk. Returns true if it extended the current
/// contiguous run; false if it started a new one — call [flush] after a
/// `false` return to get the run the gap ended.
/// contiguous run; false if it started a new one — check
/// [hasCompletedRun] (not this return value) to know when a finished run
/// is ready for [flush].
bool add(ConsoleLogChunk chunk) {
final contiguous = _lastIndex != null &&
// record_index is a u8 — allow wraparound at 0xFF, matching the
Expand Down
22 changes: 22 additions & 0 deletions test/control_plane_offsets_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,28 @@ void main() {
expect(r.add(parseConsoleLog(logPacket(10, '!'))!), isTrue);
expect(r.flush(), 'after the gap!');
});

test(
'a caller that only flushes on hasCompletedRun keeps a 4-chunk line '
'whole, even though every add() returns false on a fresh instance',
() {
// add() returning false on the very first chunk into a fresh instance
// used to be indistinguishable from a real gap. A caller that flushed
// on every `false` (the old documented contract) reset _lastIndex each
// time, so record_index 5/6/7/8 came back as four single-chunk
// fragments instead of one line.
final r = ConsoleLogReassembler();
for (final chunk in [
logPacket(5, 'BLE_'),
logPacket(6, 'CMD: '),
logPacket(7, 'Historical '),
logPacket(8, 'Data\n'),
]) {
r.add(parseConsoleLog(chunk)!);
if (r.hasCompletedRun) r.flush();
}
expect(r.flush(), 'BLE_CMD: Historical Data\n');
});
});

group('HELLO battery scan starts on the body, not the status byte', () {
Expand Down
Loading