Handle S300 alternate tail RPM frames
This commit is contained in:
parent
c2f92db217
commit
375c2510ae
@ -28,6 +28,10 @@ bool isS300PlaceholderFrame(Uint8List frame) {
|
||||
frame[16] == 0xC4;
|
||||
}
|
||||
|
||||
bool hasS300TailRpmPayload(Uint8List frame) {
|
||||
return _s300TailRpmRaw(frame) != null;
|
||||
}
|
||||
|
||||
/// Parses a 128-byte S300 ECU response frame into a [SensorState].
|
||||
/// Throws [ArgumentError] if frame length is wrong, or if [validateChecksum]
|
||||
/// is true and the NEG8 checksum fails.
|
||||
@ -39,13 +43,12 @@ SensorState parseS300(Uint8List frame, {bool validateChecksum = true}) {
|
||||
throw ArgumentError('S300 frame NEG8 checksum failed');
|
||||
}
|
||||
|
||||
// Some S300 Bluetooth frames carry live RPM in the tail payload at 82..83,
|
||||
// Some S300 Bluetooth frames carry live RPM in the tail payload,
|
||||
// while the header bytes stay fixed at 1b 00 14 00 and decode to a bogus
|
||||
// 4864 rpm. Prefer the tail value when it looks like real engine speed.
|
||||
final bool hasTailPayload = _hasS300TailPayload(frame);
|
||||
final int rpmRaw =
|
||||
hasTailPayload ? _readUint16LE(frame, 82) : _readUint16BE(frame, 2);
|
||||
final double rpm = (hasTailPayload ? rpmRaw - 1089 : rpmRaw - 256)
|
||||
final int? tailRpmRaw = _s300TailRpmRaw(frame);
|
||||
final int rpmRaw = tailRpmRaw ?? _readUint16BE(frame, 2);
|
||||
final double rpm = (tailRpmRaw != null ? rpmRaw - 1089 : rpmRaw - 256)
|
||||
.clamp(0, 12000)
|
||||
.toDouble();
|
||||
|
||||
@ -185,8 +188,11 @@ int _readUint16LE(Uint8List frame, int offset) {
|
||||
return frame[offset] | (frame[offset + 1] << 8);
|
||||
}
|
||||
|
||||
bool _hasS300TailPayload(Uint8List frame) {
|
||||
if (!isS300PlaceholderFrame(frame)) return false;
|
||||
final rpm = _readUint16LE(frame, 82);
|
||||
return rpm > 300 && rpm < 12000;
|
||||
int? _s300TailRpmRaw(Uint8List frame) {
|
||||
if (!isS300PlaceholderFrame(frame)) return null;
|
||||
for (final offset in const [82, 86]) {
|
||||
final rpm = _readUint16LE(frame, offset);
|
||||
if (rpm > 300 && rpm < 12000) return rpm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -15,6 +15,9 @@ final sensorStateProvider = StreamProvider<SensorState>((ref) async* {
|
||||
|
||||
await for (final frame in btNotifier.frameStream) {
|
||||
if (ecuType == EcuType.s300) {
|
||||
if (isS300PlaceholderFrame(frame) && !hasS300TailRpmPayload(frame)) {
|
||||
continue;
|
||||
}
|
||||
yield parseS300(frame, validateChecksum: false);
|
||||
} else {
|
||||
yield parseKPro(frame);
|
||||
|
||||
@ -190,8 +190,7 @@ void main() {
|
||||
expect(isS300PlaceholderFrame(frame), isTrue);
|
||||
});
|
||||
|
||||
test('uses calibrated tail payload RPM for S300 Bluetooth prefix frames',
|
||||
() {
|
||||
test('uses calibrated tail payload RPM at offset 82', () {
|
||||
final frame = Uint8List(128);
|
||||
final prefix = [
|
||||
0x1B,
|
||||
@ -222,5 +221,68 @@ void main() {
|
||||
final state = parseS300(frame);
|
||||
expect(state.rpm, equals(2033.0));
|
||||
});
|
||||
|
||||
test('uses calibrated tail payload RPM at offset 86', () {
|
||||
final frame = Uint8List(128);
|
||||
final prefix = [
|
||||
0x1B,
|
||||
0x00,
|
||||
0x14,
|
||||
0x00,
|
||||
0x00,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xF2,
|
||||
0x03,
|
||||
0x18,
|
||||
0x00,
|
||||
0x00,
|
||||
0x10,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xC4,
|
||||
];
|
||||
for (var i = 0; i < prefix.length; i++) {
|
||||
frame[i] = prefix[i];
|
||||
}
|
||||
frame[86] = 0x31;
|
||||
frame[87] = 0x0C;
|
||||
frame[127] = calculateNeg8(frame.sublist(0, 127));
|
||||
|
||||
expect(hasS300TailRpmPayload(frame), isTrue);
|
||||
final state = parseS300(frame);
|
||||
expect(state.rpm, equals(2032.0));
|
||||
});
|
||||
|
||||
test('detects empty S300 Bluetooth prefix frames', () {
|
||||
final frame = Uint8List(128);
|
||||
final prefix = [
|
||||
0x1B,
|
||||
0x00,
|
||||
0x14,
|
||||
0x00,
|
||||
0x00,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xF2,
|
||||
0x03,
|
||||
0x18,
|
||||
0x00,
|
||||
0x00,
|
||||
0x10,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xC4,
|
||||
];
|
||||
for (var i = 0; i < prefix.length; i++) {
|
||||
frame[i] = prefix[i];
|
||||
}
|
||||
frame[127] = calculateNeg8(frame.sublist(0, 127));
|
||||
|
||||
expect(isS300PlaceholderFrame(frame), isTrue);
|
||||
expect(hasS300TailRpmPayload(frame), isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user