92 lines
3.3 KiB
Dart
92 lines
3.3 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:dmc_app/transport/msp/msp_frame.dart';
|
|
import 'package:dmc_app/transport/msp/msp_frame_decoder.dart';
|
|
|
|
/// Fuettert [bytes] in Stuecken der Groesse [chunkSize] und sammelt alle
|
|
/// dekodierten Rahmen ueber den gesamten Strom.
|
|
List<MspFrame> _decodeInChunks(Uint8List bytes, int chunkSize) {
|
|
final decoder = MspFrameDecoder();
|
|
final frames = <MspFrame>[];
|
|
for (var offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
final end = (offset + chunkSize).clamp(0, bytes.length);
|
|
frames.addAll(decoder.addBytes(bytes.sublist(offset, end)));
|
|
}
|
|
return frames;
|
|
}
|
|
|
|
void main() {
|
|
final altitudePayload = Uint8List.fromList(
|
|
[0xD2, 0x04, 0x00, 0x00, 0xCE, 0xFF, 0xB0, 0x04, 0x00, 0x00],
|
|
);
|
|
final altitudeFrameBytes =
|
|
encodeMspV2Frame(MspDirection.response, 109, altitudePayload);
|
|
|
|
// Abnahmekriterium (Doku Kommunikationsschicht 8): dieselbe Bytefolge in
|
|
// Stuecken von 1, 7 und 512 Byte muss dasselbe Ergebnis liefern.
|
|
for (final chunkSize in [1, 7, 512]) {
|
|
test('dekodiert einen MSP_ALTITUDE-Rahmen bei Chunk-Groesse $chunkSize', () {
|
|
final frames = _decodeInChunks(altitudeFrameBytes, chunkSize);
|
|
|
|
expect(frames, hasLength(1));
|
|
expect(frames.single.direction, MspDirection.response);
|
|
expect(frames.single.function, 109);
|
|
expect(frames.single.payload, altitudePayload);
|
|
});
|
|
}
|
|
|
|
test('mehrere Rahmen hintereinander in einem Chunk werden alle erkannt', () {
|
|
final gpsFrameBytes = encodeMspV2Frame(MspDirection.response, 106,
|
|
Uint8List.fromList([1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
|
|
|
|
final combined = Uint8List.fromList([
|
|
...altitudeFrameBytes,
|
|
...gpsFrameBytes,
|
|
]);
|
|
|
|
final frames = _decodeInChunks(combined, 512);
|
|
|
|
expect(frames, hasLength(2));
|
|
expect(frames[0].function, 109);
|
|
expect(frames[1].function, 106);
|
|
});
|
|
|
|
test('fehlerhafte CRC wird verworfen, ohne den Strom zu verlieren', () {
|
|
final corrupted = Uint8List.fromList(altitudeFrameBytes);
|
|
corrupted[corrupted.length - 1] ^= 0xFF; // letztes Byte (CRC) kippen
|
|
|
|
final decoder = MspFrameDecoder();
|
|
final framesFromCorrupted = decoder.addBytes(corrupted);
|
|
expect(framesFromCorrupted, isEmpty);
|
|
|
|
// Direkt danach ein gueltiger Rahmen auf demselben Decoder - der
|
|
// Automat muss wieder im Idle-Zustand sein und normal weiterlesen.
|
|
final framesFromValid = decoder.addBytes(altitudeFrameBytes);
|
|
expect(framesFromValid, hasLength(1));
|
|
expect(framesFromValid.single.function, 109);
|
|
});
|
|
|
|
test('Fehlerantwort (dir = \'!\') wird als solche erkannt', () {
|
|
final errorFrameBytes =
|
|
encodeMspV2Frame(MspDirection.error, 109, Uint8List(0));
|
|
|
|
final frames = MspFrameDecoder().addBytes(errorFrameBytes);
|
|
|
|
expect(frames, hasLength(1));
|
|
expect(frames.single.direction, MspDirection.error);
|
|
expect(frames.single.function, 109);
|
|
});
|
|
|
|
test('Muell vor dem eigentlichen Rahmen wird ignoriert', () {
|
|
final garbage = Uint8List.fromList([0x00, 0x24, 0x11, 0x58, 0xFF]);
|
|
final combined = Uint8List.fromList([...garbage, ...altitudeFrameBytes]);
|
|
|
|
final frames = _decodeInChunks(combined, 7);
|
|
|
|
expect(frames, hasLength(1));
|
|
expect(frames.single.function, 109);
|
|
});
|
|
}
|