import '../../domain/waypoint/flat_waypoint_list.dart'; import '../flight_controller_link.dart'; import '../link_transport.dart'; import 'msp_client.dart'; import 'msp_commands.dart'; import 'msp_telemetry_codec.dart'; import 'msp_telemetry_poller.dart'; /// iNAV-Anbindung via MSP (Architektur-Doku 3.1), umgesetzt gegen den /// tatsaechlichen iNAV-9.1.0-Quellcode (Doku Kommunikationsschicht Abschnitt /// 4 - Befehlsnummern/Byte-Layouts gegen `msp_protocol.h`, /// `msp_protocol_v2_inav.h` und `fc_msp.c` geprueft, nicht aus dem /// Gedaechtnis uebernommen). /// /// Kennt nur die protokollneutrale [LinkTransport]-Abstraktion (Doku /// Kommunikationsschicht Abschnitt 2) - ob darunter Bluetooth Classic (MVP) /// oder spaeter WLAN/UDP steckt, ist fuer diese Klasse unsichtbar. /// /// Setzt die in der Doku vorgegebene Reihenfolge um: Rahmen kodieren/ /// dekodieren + Telemetrie lesen (dieser Schritt). Missionsupload, /// Flugmodus-Wechsel und Armen sind bewusst noch nicht umgesetzt (Doku 4, /// "Reihenfolge der Umsetzung": "Erst danach Missionsupload") - das sind /// eigene, sicherheitsrelevante Schritte (u.a. `MSP_SET_WP`), die eigene /// Sorgfalt brauchen. class MspFlightControllerLink implements FlightControllerLink { MspFlightControllerLink({required this.transport}); final LinkTransport transport; MspClient? _client; MspTelemetryPoller? _poller; @override FcCapabilities get capabilities => const FcCapabilities( supportsMultiMission: true, supportsInFlightUpload: false, // Konservativer iNAV-Default (navigation.h: NAV_MAX_WAYPOINTS = 15). // Viele Boards/Targets erlauben mehr; ohne eine MSP_WP_GETINFO- // Abfrage (Teil des noch nicht umgesetzten Missions-Uploads) nicht // praeziser bestimmbar. maxWaypoints: 15, ); @override Future connect() async { await transport.connect(); final client = MspClient(transport); _client = client; final poller = MspTelemetryPoller(client); _poller = poller; poller.start(); } @override Future disconnect() async { await _poller?.dispose(); _poller = null; _client?.dispose(); _client = null; await transport.disconnect(); } @override Future uploadMission(FlatWaypointList mission) => throw UnimplementedError( 'Missions-Upload (MSP_SET_WP) ist noch nicht umgesetzt - Doku ' 'Kommunikationsschicht 4 sieht das erst nach dem Telemetrie-Schritt vor.', ); @override Future setFlightMode(FlightMode mode) => throw UnimplementedError( 'Flugmodus-Wechsel ist noch nicht umgesetzt.', ); @override Future arm() => throw UnimplementedError( 'Armen ueber MSP ist noch nicht umgesetzt.', ); @override Stream subscribeTelemetry() { final poller = _poller; if (poller == null) { throw StateError('subscribeTelemetry() vor connect() aufgerufen.'); } return poller.frames; } @override Future readActiveWaypointIndex() async { final client = _client; if (client == null) { throw StateError('readActiveWaypointIndex() vor connect() aufgerufen.'); } return parseMspNavStatusActiveWaypoint( await client.request(MspCommands.navStatus), ); } }