Skip S300 placeholders after raw receipt
This commit is contained in:
parent
2b537728dc
commit
5df3442523
@ -87,12 +87,6 @@ class BtPoller {
|
|||||||
final Uint8List frame =
|
final Uint8List frame =
|
||||||
Uint8List.fromList(_rxBuf.sublist(startIdx, startIdx + 128));
|
Uint8List.fromList(_rxBuf.sublist(startIdx, startIdx + 128));
|
||||||
|
|
||||||
if (ecuType == EcuType.s300 && _isS300PlaceholderFrame(frame)) {
|
|
||||||
droppedFrames++;
|
|
||||||
_rxBuf.removeRange(0, startIdx + 128);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final checksumOk = validateFrame(frame);
|
final checksumOk = validateFrame(frame);
|
||||||
final canUseFrame = checksumOk || ecuType == EcuType.s300;
|
final canUseFrame = checksumOk || ecuType == EcuType.s300;
|
||||||
|
|
||||||
@ -125,31 +119,4 @@ class BtPoller {
|
|||||||
stop();
|
stop();
|
||||||
_frameController.close();
|
_frameController.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isS300PlaceholderFrame(Uint8List frame) {
|
|
||||||
if (frame.length != 128) return false;
|
|
||||||
|
|
||||||
// The S300 Bluetooth stream can interleave a valid-checksum placeholder
|
|
||||||
// frame that is not the SManager live sensor frame. It has a fixed header
|
|
||||||
// and zero/overflow values for speed, TPS, injection and ignition, then it
|
|
||||||
// overwrites the dashboard with stale/empty values. Filter only this exact
|
|
||||||
// signature so true idle/stopped live frames can still pass.
|
|
||||||
return frame[0] == 0x1B &&
|
|
||||||
frame[1] == 0x00 &&
|
|
||||||
frame[2] == 0x14 &&
|
|
||||||
frame[3] == 0x00 &&
|
|
||||||
frame[4] == 0x00 &&
|
|
||||||
frame[5] == 0xFF &&
|
|
||||||
frame[6] == 0xFF &&
|
|
||||||
frame[7] == 0xF2 &&
|
|
||||||
frame[8] == 0x03 &&
|
|
||||||
frame[9] == 0x18 &&
|
|
||||||
frame[10] == 0x00 &&
|
|
||||||
frame[11] == 0x00 &&
|
|
||||||
frame[12] == 0x10 &&
|
|
||||||
frame[13] == 0x00 &&
|
|
||||||
frame[14] == 0x00 &&
|
|
||||||
frame[15] == 0x00 &&
|
|
||||||
frame[16] == 0xC4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,33 @@ import 'sensor_state.dart';
|
|||||||
import 'temp_table.dart';
|
import 'temp_table.dart';
|
||||||
import 'neg8.dart';
|
import 'neg8.dart';
|
||||||
|
|
||||||
|
bool isS300PlaceholderFrame(Uint8List frame) {
|
||||||
|
if (frame.length != 128) return false;
|
||||||
|
|
||||||
|
// The S300 Bluetooth stream can interleave a valid-checksum placeholder
|
||||||
|
// frame that is not the SManager live sensor frame. It has a fixed header
|
||||||
|
// and zero/overflow values for speed, TPS, injection and ignition, then it
|
||||||
|
// overwrites the dashboard with stale/empty values. Keep this check near the
|
||||||
|
// parser so Bluetooth diagnostics can still receive and count raw frames.
|
||||||
|
return frame[0] == 0x1B &&
|
||||||
|
frame[1] == 0x00 &&
|
||||||
|
frame[2] == 0x14 &&
|
||||||
|
frame[3] == 0x00 &&
|
||||||
|
frame[4] == 0x00 &&
|
||||||
|
frame[5] == 0xFF &&
|
||||||
|
frame[6] == 0xFF &&
|
||||||
|
frame[7] == 0xF2 &&
|
||||||
|
frame[8] == 0x03 &&
|
||||||
|
frame[9] == 0x18 &&
|
||||||
|
frame[10] == 0x00 &&
|
||||||
|
frame[11] == 0x00 &&
|
||||||
|
frame[12] == 0x10 &&
|
||||||
|
frame[13] == 0x00 &&
|
||||||
|
frame[14] == 0x00 &&
|
||||||
|
frame[15] == 0x00 &&
|
||||||
|
frame[16] == 0xC4;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a 128-byte S300 ECU response frame into a [SensorState].
|
/// Parses a 128-byte S300 ECU response frame into a [SensorState].
|
||||||
/// Throws [ArgumentError] if frame length is wrong, or if [validateChecksum]
|
/// Throws [ArgumentError] if frame length is wrong, or if [validateChecksum]
|
||||||
/// is true and the NEG8 checksum fails.
|
/// is true and the NEG8 checksum fails.
|
||||||
|
|||||||
@ -7,18 +7,22 @@ import '../protocol/sensor_state.dart';
|
|||||||
import 'bt_provider.dart';
|
import 'bt_provider.dart';
|
||||||
import 'settings_provider.dart';
|
import 'settings_provider.dart';
|
||||||
|
|
||||||
/// Emits a parsed [SensorState] for every valid frame received from the ECU.
|
/// Emits a parsed [SensorState] for every live data frame received from the ECU.
|
||||||
/// Automatically picks S300 or KPro parser based on [settingsProvider].
|
/// Automatically picks S300 or KPro parser based on [settingsProvider].
|
||||||
final sensorStateProvider = StreamProvider<SensorState>((ref) {
|
final sensorStateProvider = StreamProvider<SensorState>((ref) async* {
|
||||||
final ecuType = ref.watch(settingsProvider).ecuType;
|
final ecuType = ref.watch(settingsProvider).ecuType;
|
||||||
final btNotifier = ref.watch(btProvider.notifier);
|
final btNotifier = ref.watch(btProvider.notifier);
|
||||||
|
|
||||||
return btNotifier.frameStream.map((frame) {
|
await for (final frame in btNotifier.frameStream) {
|
||||||
if (ecuType == EcuType.s300) {
|
if (ecuType == EcuType.s300) {
|
||||||
return parseS300(frame, validateChecksum: false);
|
if (isS300PlaceholderFrame(frame)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
yield parseS300(frame, validateChecksum: false);
|
||||||
|
} else {
|
||||||
|
yield parseKPro(frame);
|
||||||
}
|
}
|
||||||
return parseKPro(frame);
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Last successfully parsed sensor state (never null after first frame).
|
/// Last successfully parsed sensor state (never null after first frame).
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:hvbt_dash/core/protocol/neg8.dart';
|
||||||
import 'package:hvbt_dash/core/protocol/s300_parser.dart';
|
import 'package:hvbt_dash/core/protocol/s300_parser.dart';
|
||||||
import 'package:hvbt_dash/core/protocol/temp_table.dart';
|
import 'package:hvbt_dash/core/protocol/temp_table.dart';
|
||||||
|
|
||||||
@ -159,5 +160,34 @@ void main() {
|
|||||||
final state = parseS300(frame, validateChecksum: false);
|
final state = parseS300(frame, validateChecksum: false);
|
||||||
expect(state.rpm, equals(1000.0));
|
expect(state.rpm, equals(1000.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('detects known S300 placeholder frame', () {
|
||||||
|
final frame = Uint8List(128);
|
||||||
|
final signature = [
|
||||||
|
0x1B,
|
||||||
|
0x00,
|
||||||
|
0x14,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xF2,
|
||||||
|
0x03,
|
||||||
|
0x18,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x10,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0xC4,
|
||||||
|
];
|
||||||
|
for (var i = 0; i < signature.length; i++) {
|
||||||
|
frame[i] = signature[i];
|
||||||
|
}
|
||||||
|
frame[127] = calculateNeg8(frame.sublist(0, 127));
|
||||||
|
|
||||||
|
expect(isS300PlaceholderFrame(frame), isTrue);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user