import 'dart:async'; import 'dart:typed_data'; import '../link_transport.dart'; /// Transport ohne echte Gegenstelle (Doku Kommunikationsschicht Abschnitt 2/9): /// erlaubt UI- und MSP-Entwicklung ohne Bluetooth-Hardware oder SITL. Bytes, /// die die Gegenstelle "gesendet" haette, werden ueber [feed] eingespeist; /// [sentData] sammelt, was die App darueber gesendet hat, damit Tests das /// pruefen koennen. class LoopbackTransport implements LinkTransport { final _incomingController = StreamController.broadcast(); final _stateController = StreamController.broadcast(); LinkState _state = LinkState.disconnected; LinkErrorReason? _lastErrorReason; String? _lastErrorMessage; /// Alle bisher per [send] geschickten Bytes, in Reihenfolge. final List sentData = []; @override Stream get incoming => _incomingController.stream; @override Stream get state => _stateController.stream; @override LinkErrorReason? get lastErrorReason => _lastErrorReason; @override String? get lastErrorMessage => _lastErrorMessage; /// Simuliert eingehende Bytes von der Gegenstelle (z.B. aufgezeichnete /// MSP-Antworten, Doku Abschnitt 9). void feed(Uint8List data) => _incomingController.add(data); /// Simuliert einen Verbindungsfehler, z.B. um Fehlerbehandlung in der /// Oberflaeche ohne Hardware zu testen. void simulateError(LinkErrorReason reason, [String? message]) { _lastErrorReason = reason; _lastErrorMessage = message; _setState(LinkState.error); } @override Future connect() async { _lastErrorReason = null; _lastErrorMessage = null; _setState(LinkState.connecting); _setState(LinkState.connected); } @override Future disconnect() async { _setState(LinkState.disconnected); } @override Future send(Uint8List data) async { sentData.add(data); } @override void dispose() { _incomingController.close(); _stateController.close(); } void _setState(LinkState next) { _state = next; if (!_stateController.isClosed) _stateController.add(next); } LinkState get currentState => _state; }