feat(display): Sprint 7 — USB serial link to AR-Concentrador via NMEA $PARP

- Add flutter_libserialport dependency (pubspec.yaml)
- New ParpCodec: XOR-checksum NMEA parser + command builders for all PARP sentences
- New ConcentradorService: manages two independent COM ports (RX-OUT broadcast,
  TX-IN commands) at 115200/8N1; auto-fires onConnectionChanged on link drop
- AutopilotState: dual-mode operation (demo timer OR live serial); connectToSerial /
  disconnectSerial; command methods (engage/disengage/adjustSetpoint) forward to
  ConcentradorService when connected; falls back to demo on disconnect
- New PortSettingsScreen (/settings/ports): RX+TX dropdowns populated from
  SerialPort.availablePorts, persisted in SharedPreferences; Connect/Disconnect
  buttons with error display and snackbar feedback
- main.dart: auto-connect to saved ports on startup (silent fail → demo mode);
  registers /settings/ports route
- CockpitScreen: gear icon replaced with PopupMenuButton (Puertos COM / Apariencia)

AR_electronics — AR-Autopilot Project
This commit is contained in:
2026-05-24 01:28:04 -04:00
parent c946d2df6d
commit abe9b764c7
7 changed files with 886 additions and 81 deletions
@@ -31,6 +31,7 @@ import '../../widgets/themed/mode_selector.dart';
import '../../widgets/themed/rudder_indicator.dart';
import '../../widgets/themed/status_chip.dart';
import '../settings/appearance_settings.dart';
import '../settings/port_settings_screen.dart';
class CockpitScreen extends StatelessWidget {
const CockpitScreen({super.key});
@@ -138,14 +139,47 @@ class _TopBar extends StatelessWidget {
status: ap.isConnected ? StatusLevel.ok : StatusLevel.warn,
),
const SizedBox(width: 16),
GestureDetector(
onTap: () => Navigator.pushNamed(
context, AppearanceSettingsScreen.routeName),
child: Icon(
PopupMenuButton<String>(
icon: Icon(
Icons.settings_outlined,
color: theme.textMuted,
size: 22,
),
color: theme.backgroundMid,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: theme.panelBorder),
),
onSelected: (route) => Navigator.pushNamed(context, route),
itemBuilder: (_) => [
PopupMenuItem(
value: PortSettingsScreen.routeName,
child: Row(
children: [
Icon(Icons.usb, color: theme.accentMid, size: 18),
const SizedBox(width: 10),
Text(
'Puertos COM',
style: TextStyle(color: theme.textMain, fontSize: 13),
),
],
),
),
PopupMenuItem(
value: AppearanceSettingsScreen.routeName,
child: Row(
children: [
Icon(Icons.palette_outlined,
color: theme.accentMid, size: 18),
const SizedBox(width: 10),
Text(
'Apariencia',
style: TextStyle(color: theme.textMain, fontSize: 13),
),
],
),
),
],
),
],
),