107 lines
3.7 KiB
Dart
107 lines
3.7 KiB
Dart
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<void> connect() async {
|
|
// Idempotent (Doku flightControllerLinkProvider: "Verbindung bleibt
|
|
// ueber Moduswechsel hinweg aktiv") - jeder erneute Eintritt in den
|
|
// Fly-Modus ruft connect() erneut auf derselben, weiterhin
|
|
// bestehenden Instanz auf; ohne diese Sperre wuerde das einen zweiten
|
|
// MspClient/-Poller nebenher starten, der um MSP-Antworten race
|
|
// (MSP kennt keine Request-IDs, siehe MspClient-Doku).
|
|
if (_poller != null) return;
|
|
await transport.connect();
|
|
final client = MspClient(transport);
|
|
_client = client;
|
|
final poller = MspTelemetryPoller(client);
|
|
_poller = poller;
|
|
poller.start();
|
|
}
|
|
|
|
@override
|
|
Future<void> disconnect() async {
|
|
await _poller?.dispose();
|
|
_poller = null;
|
|
_client?.dispose();
|
|
_client = null;
|
|
await transport.disconnect();
|
|
}
|
|
|
|
@override
|
|
Future<void> 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<void> setFlightMode(FlightMode mode) => throw UnimplementedError(
|
|
'Flugmodus-Wechsel ist noch nicht umgesetzt.',
|
|
);
|
|
|
|
@override
|
|
Future<void> arm() => throw UnimplementedError(
|
|
'Armen ueber MSP ist noch nicht umgesetzt.',
|
|
);
|
|
|
|
@override
|
|
Stream<TelemetryFrame> subscribeTelemetry() {
|
|
final poller = _poller;
|
|
if (poller == null) {
|
|
throw StateError('subscribeTelemetry() vor connect() aufgerufen.');
|
|
}
|
|
return poller.frames;
|
|
}
|
|
|
|
@override
|
|
Future<int?> readActiveWaypointIndex() async {
|
|
final client = _client;
|
|
if (client == null) {
|
|
throw StateError('readActiveWaypointIndex() vor connect() aufgerufen.');
|
|
}
|
|
return parseMspNavStatusActiveWaypoint(
|
|
await client.request(MspCommands.navStatus),
|
|
);
|
|
}
|
|
}
|