import 'dart:typed_data'; /// Transportzustand, protokollneutral (Doku Kommunikationsschicht Abschnitt 2). enum LinkState { disconnected, connecting, connected, error } /// Grund eines [LinkState.error] (Doku Abschnitt 3, Robustheit/Abnahme): /// Bluetooth aus und Berechtigung abgelehnt brauchen jeweils einen eigenen, /// erklaerenden Hinweis in der Oberflaeche statt eines generischen /// "Verbindung fehlgeschlagen". enum LinkErrorReason { /// Bluetooth-Adapter ist aus. Kann ab Android 12 nicht mehr programmatisch /// eingeschaltet werden - die Oberflaeche muss zu den Systemeinstellungen /// verlinken. bluetoothOff, /// Berechtigung wurde abgelehnt, darf aber erneut angefragt werden. permissionDenied, /// Berechtigung wurde dauerhaft abgelehnt ("nicht mehr fragen"). Android /// zeigt den Dialog kein zweites Mal - die Oberflaeche muss zu den /// App-Einstellungen verlinken. permissionDeniedPermanently, /// Kein gekoppeltes Zielgeraet konnte automatisch bestimmt werden (weder /// gemerkte MAC-Adresse noch ein Geraet mit "mLRS"-Praefix). Die /// Oberflaeche muss eine Auswahlliste der gekoppelten Geraete anbieten. deviceSelectionRequired, /// Verbindungsaufbau zum bestimmten Geraet ist fehlgeschlagen oder wurde /// getrennt. connectionFailed, /// Sonstiger, nicht naeher klassifizierter Fehler. unknown, } /// Protokollneutrale Transportschnittstelle (Doku Kommunikationsschicht /// Abschnitt 2). Alles oberhalb (MSP-Encoder/-Decoder) programmiert /// ausschliesslich gegen diese Schnittstelle - kein Import von Bluetooth- /// oder Netzwerkpaketen ausserhalb von transport/. /// /// Implementierungen: BluetoothClassicTransport (MVP), UdpTransport /// (spaeter, Doku Abschnitt 6), LoopbackTransport (Tests/Entwicklung ohne /// Hardware). abstract class LinkTransport { Stream get incoming; Stream get state; /// Grund des zuletzt gemeldeten [LinkState.error], oder null solange kein /// Fehler aufgetreten ist bzw. nach erfolgreicher Verbindung. LinkErrorReason? get lastErrorReason; /// Freitext zum zuletzt gemeldeten Fehler, fuer Diagnose/Verbindungsprotokoll /// (Doku Abschnitt 7). Nicht fuer die direkte Nutzeranzeige gedacht - dafuer /// dient [lastErrorReason]. String? get lastErrorMessage; Future send(Uint8List data); Future connect(); Future disconnect(); void dispose(); } /// Wird von [LinkTransport.connect] geworfen, wenn der Verbindungsaufbau /// vorab (also bevor ueberhaupt eine Socket-Verbindung versucht wird) /// erkennbar scheitert - z.B. Bluetooth aus, Berechtigung fehlt, oder kein /// Geraet automatisch bestimmbar. Der gleiche [reason] wird zeitgleich ueber /// [LinkTransport.state]/[LinkTransport.lastErrorReason] gemeldet, damit /// sowohl der aufrufende Code (durch Warten auf [LinkTransport.connect]) /// als auch reine Beobachter der Zustands-Streams reagieren koennen. class LinkConnectException implements Exception { const LinkConnectException(this.reason, this.message); final LinkErrorReason reason; final String message; @override String toString() => 'LinkConnectException($reason): $message'; }