Files
alro65 abe9b764c7 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
2026-05-24 01:28:04 -04:00

71 lines
2.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'data/autopilot_state.dart';
import 'theme/theme_provider.dart';
import 'screens/cockpit/cockpit_screen.dart';
import 'screens/settings/appearance_settings.dart';
import 'screens/settings/port_settings_screen.dart';
// SharedPreferences keys — must match port_settings_screen.dart
const _kRxKey = 'port.rx';
const _kTxKey = 'port.tx';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Load persisted theme before first frame.
final themeProvider = await AutopilotThemeProvider.load();
// Create state object early so we can attempt auto-connect.
final autopilotState = AutopilotState();
// Attempt to reconnect to the last-used COM ports silently.
// If the ports are not available (hardware unplugged, different PC, etc.)
// the exception is swallowed and the UI stays in demo mode.
try {
final prefs = await SharedPreferences.getInstance();
final rxPort = prefs.getString(_kRxKey);
final txPort = prefs.getString(_kTxKey);
if (rxPort != null && txPort != null) {
await autopilotState.connectToSerial(rxPort: rxPort, txPort: txPort);
}
} catch (_) {
// Hardware not available — stay in demo mode.
}
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AutopilotThemeProvider>.value(
value: themeProvider,
),
ChangeNotifierProvider<AutopilotState>.value(
value: autopilotState,
),
],
child: const ArAutopilotApp(),
),
);
}
class ArAutopilotApp extends StatelessWidget {
const ArAutopilotApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AR-Autopilot',
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
initialRoute: CockpitScreen.routeName,
routes: {
CockpitScreen.routeName: (_) => const CockpitScreen(),
AppearanceSettingsScreen.routeName: (_) => const AppearanceSettingsScreen(),
PortSettingsScreen.routeName: (_) => const PortSettingsScreen(),
},
);
}
}